부부의 코딩 성장 일기

LeetCode 78(Subsets, Python) 본문

Algorithm/LeetCode

LeetCode 78(Subsets, Python)

펩시_콜라 2024. 1. 25. 19:00

1. 문제 링크

 

Subsets - LeetCode

Can you solve this real interview question? Subsets - Given an integer array nums of unique elements, return all possible subsets (the power set). The solution set must not contain duplicate subsets. Return the solution in any order.   Example 1: Input: n

leetcode.com

2. 문제 설명

  • unique elements로 구성된 array nums가 주어졌을 때, 모든 가능한 subsets를 반환
    • 중복 subsets는 허용하지 않으며, 어떤 순서로든 반환 가능
  • 예시1) nums = [1,2,3], output = [[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
  • 예시2) nums = [0], output = [[], [0]]

3. 처음 풀이 

  • 최근 backtracker 문제를 연속으로 두번 풀어서 이번에도 문제를 보고 backtracker로 접근하였음
  • backtrack함수는 path, start, num 세가지 인자를 받고
    • 만약 path의 길이가 num과 동일하면 output에 해당 path를 append 시키고, 
    • nums 에 대해 start 부터 for문을 돌면서, path에 nums[i]가 포함되있지 않으면,
      • path에 append한 후, start를 i+1로 변경하여 backtracker를 호출 후 원래 상태로 원복 (path.pop())
    • 그리고 num가 1보다 큰 경우에는 num을 하나 줄인 backtrack함수를 호출
  • 여기서 문제는 backtrack을 두번 호출한다는 것 . runtime이 70%도 나오긴 했지만, 대부분이 하위 10%에서 머물렀음
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:

        def backtrack(path, start, num):
            if len(path) == num:
                output.append(path.copy())
                return

            else:
                for i in range(start, len(nums)):
                    if nums[i] not in path:
                        path.append(nums[i])
                        backtrack(path,i+1,num)
                        path.pop()
                    if num > 1:
                        backtrack(path,i+1,num-1)

        output = [[]]
        backtrack([],0,len(nums))

        return output

 

4. 다른 풀이 

  • 처음에 나는 다양한 길이의 list를 append해야 하므로, len(nums)를 인자로 받고, 이를 1이 될 때까지 줄여나갔는데 
  • 굳이 그렇게 할 필요가 없었다!! 
  • 생각해보면, 그냥 return하는 조건을 걸지 않고, 
    • for문을 돌리면서 그 값을 그냥 output에 append 시켜도,
    • len(nums)이하 길이의 list만 output에 append 되기 때문에
    • 위에서 한 것처럼 복잡한 조건을 추가할 필요가 없었다. 
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:

        def backtrack(start, path):
            output.append(path[:])

            for i in range(start, len(nums)):
                path.append(nums[i])
                backtrack(i + 1, path)
                path.pop()

        output = []
        backtrack(0, [])
        return output

 

  • 제로_콜라의 풀이 
    • backtracker로 재귀를 쓰지 않고, 깔끔하게 풀었다. 
    • nums가 [1,2,3]이면 
      • 처음에는 result가 [[], [1]] 이 되고, 
      • 그 다음 iteration에서는 [[],[1],[2],[1,2]]가 되고
      • 마지막 iteration에서는 [[],[1],[2],[1,2],[1,3],[2,3],[1,2,3]]이 되는 구조로 간단히 for문으로 해결
class Solution:
    def subsets(self, nums: List[int]) -> List[List[int]]:
        result = [[]]
        for num in nums:
            for subset in result[:]:
                result.append(subset + [num])
        
        return result

 

5. 배운 점 

  • backtracker 익숙해지기! + 다른 algorithm, 로직으로도 해결 가능.