하지만 각 row는 이전 row(dp[i - 1])만 보기 때문에, 1D DP로 space optimize가 가능하다.
또한, list가 아닌 defaultdict로 관리하면 필요한 값만 저장할 수 있기 때문에 space 측면에서 더 이점을 볼 수 있을 것 같다. (근데 무조건 좋기만 할까..? list와 dict 모두 python에서는 O(1)에 접근가능하지만, 실제로 시간에 차이가 날 수도 있지 않을까)
이런 패턴은 기억해두자...!
def findTargetSumWays(self, nums: List[int], target: int) -> int:
from collections import defaultdict
dp = defaultdict(int)
dp[0] = 1 # base case
for num in nums:
tmp = defaultdict(int)
for tot, cnt in dp.items():
tmp[tot + num] += cnt
tmp[tot - num] += cnt
dp = tmp
return dp[target]
Approach
Idea 1: Backtracking + Memo
일반적인 backtracking을 시도하면 TLE가 발생한다. (한 번 호출 당 2번(
pos
,neg
)의 호출 ->O(2^n)
)따라서 결과를 memoization 하는 방법을 사용해야 하는데, 이를 위해서는
memo
hash table을 사용하거나,@cache
decorator를 사용하면 된다.⬇️ backtracking에서
memo
hash table을 사용하려면, 다음과 같은 구조로 사용하면 된다.Idea 2: DP (2D -> 1D)
다음과 같이 2D DP로 풀 수 있다. (0/1 knapsack)
하지만 각 row는 이전 row(
dp[i - 1]
)만 보기 때문에, 1D DP로 space optimize가 가능하다.또한,
list
가 아닌defaultdict
로 관리하면 필요한 값만 저장할 수 있기 때문에 space 측면에서 더 이점을 볼 수 있을 것 같다. (근데 무조건 좋기만 할까..?list
와dict
모두 python에서는O(1)
에 접근가능하지만, 실제로 시간에 차이가 날 수도 있지 않을까)이런 패턴은 기억해두자...!
Complexity (?! - 다시 고민해봐야 할 듯)
O(l * n)
(memo
가 단 한 번 채워짐)O(l * n)
O(l * n)
(memo
, recursion stack)O(l)