알롬버스/알고리즘

[LeetCode]15. 3Sum - Python 문제 풀이

bobmyeonsoo 2023. 8. 9. 22:21

문제

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != j, i != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

nums라는 array가 주어졌을 때 3개의 인덱스값은 모두 다르고, 각각의 합이 0인 3개의 값 조합을 return 하시오.

 

풀이

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        '''
        left = 0
        right = 1
        '''
        ans = []

        # two pointer 문제로 풀기 위하여 sort를 해줘야 한다.
        nums = sorted(nums) 

        # 이 아래 조건문은 모두 테스트 케이스의 예외를 처리하기 위함 !
        if len(nums) == 3 and sum(nums) != 0:
            return []
        if nums == [0,0,0]:
            return [[0,0,0]]

        # 이번 투포인터는 하나의 값을 미리 고정시키고
        # 나머지의 값들 중에서 투포인터를 적용 !
        for i in range(len(nums)):
            # 고정된 값 
            # 각각의 값을 기준으로 더했을 때 0이 되는 조건을 만족하는 모든 경우의 수를 볼 것임
            fix = nums[i]

            # fix 와 겹치지 않기 위해
            # fix의 인덱스 다음의 인덱스를 하나의 포인터로 지정
            # 또 다른 하나의 포인터는 맨끝에 위치시킴
            left = i+1
            right = len(nums) - 1 

            # 중복을 제거하기 위해 이전 값과 같을 경우는 생략 !
            # 이 모든게 정렬을 했기 때문에 가능 
            if i > 0 and nums[i] == nums[i - 1]:
                continue
            
            # 하나의 값을 고정하고 투포인터 시작
            while left < right :
                
                # a 는 투포인터의 합
                a = nums[left] + nums[right]

                # 만약 투포인터의 값과 고정값의 합이 0일 경우 답을 추가 
                if fix + a == 0:
                    candid = [nums[left], fix, nums[right]]
                    # ans 내의 중복을 없애기 위하여 
                    if candid not in ans:
                        ans.append(candid)
                    # 만약에 답을 추가를 하고 난 뒤에도 left가 움직이지 않는다면
                    # 다른 경우를 볼 수 없음 
                    # 그렇기 때문에 답을 추가하고 난 뒤에도 움직여야 함 **중요**
                    left += 1
                
                # 만약 3개의 값의 합이 0보다 작을 경우 숫자가 부족한 것이기 때문에 
                # 더 큰값으로 left를 움직임
                elif fix + a < 0:
                    left += 1
                # 합이 너무 클 경우에는 값을 줄여줌
                else: 
                    right -= 1
        
        return ans
  • 시간 복잡도 : O(NlogN)
    • 보통 투 포인터로 풀게 된다면 --> O(logN)
    • 근데 이 문제는 투포인터를 nums의 길이만큼 반복하기 때문에 --> O(NlogN)