석박사/박사 유학 준비
Leetcode Dynamic Programming 정복 커리큘럼
밍이의 꿈
2022. 11. 9. 04:54
좋은 솔루션을 접하지 않은 채로 여러 문제를 풀어보다보면 논리가 계속 꼬이고 코드가 복잡해지는것을 느낄 수 있을 것이다. 아래 영상은 Dynamic programming 문제들을 5가지 패턴으로 유형화하여 제시한다.
생각의 논리 전개는 다음과 같이 진행하는게 좋다.
Step1. 간단한 예시를 이용해 Brute-force decision tree 그려보기 -- 이때 주로 time complexity 가 O(n). 그 후 타임아웃이 뜰 것을 염두에 두면서 recursive function을 구현해보기.
Step2. 그린 Decision tree 예시를 보면서 겹치는 연산을 찾아내기. 이를 memoization 할 방법을 고민해보기. 1-d array 일수도, 2-d array 일 수도 있다. 인덱싱에서 꼬이지 않게 유의하고, array 각 칸의 의미를 잘 생각해보기. (특히 0과 1 같은 코너케이스의 의미)
Step3. Space complexity 도 더 줄이고 싶다면 bottom up 방법 고민해보기. 오른쪽에서 왼쪽으로, 아래에서 위로 역산한다.
대충 솔루션만 보고 넘기지 않고 적은 문제를 풀더라도 이 세스텝을 모두 구현해보는게 좋다.
https://www.youtube.com/watch?v=mBNrRy2_hVs&t=41
이 아래는 내가 짠 솔루션 코드를 공개한다.
70.Climbing Stairs
class Solution(object):
def climbStairs(self, n):
"""
:type n: int
:rtype: int
"""
# corner case
if n == 1:
return 1
elif n == 2:
return 2
# bottom up
a, b = 1, 2
for i in range(n-2, 0, -1): #n-3, ..., 0
new_b = a + b
a = b
b = new_b
return b
# # recursive & memoization
# stairs_array = [0] + [None for _ in range(n)]
# stairs_array[1] = 1
# stairs_array[2] = 2
# def stairs(n):
# if stairs_array[n-1] is None:
# stairs_array[n-1] = stairs(n-1)
# if stairs_array[n-2] is None:
# stairs_array[n-2] = stairs(n-2)
# stairs_array[n] = stairs_array[n-1] + stairs_array[n-2]
# return stairs_array[n]
# return stairs(n)
416. Partition Equal Subset Sum
class Solution(object):
def canPartition(self, nums):
"""
:type nums: List[int]
:rtype: bool
"""
# bottom up
dp = {0}
for i in range(len(nums)-1, -1, -1):
new_dp = set()
for current_sum in dp:
new_dp.add(current_sum + nums[i])
new_dp.add(current_sum - nums[i])
dp = new_dp
for e in dp:
if e == 0:
return True
return False
1143. Longest Common Subsequence