From 2665d5bae877907e27937d2bd6a9d5677cfae37c Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 26 Aug 2022 11:56:02 -0400 Subject: [PATCH 01/57] #153 update --- ...53-Find-Minimum-in-Rotated-Sorted-Array.py | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/python/153-Find-Minimum-in-Rotated-Sorted-Array.py b/python/153-Find-Minimum-in-Rotated-Sorted-Array.py index e36c53238..848910079 100644 --- a/python/153-Find-Minimum-in-Rotated-Sorted-Array.py +++ b/python/153-Find-Minimum-in-Rotated-Sorted-Array.py @@ -1,16 +1,10 @@ class Solution: def findMin(self, nums: List[int]) -> int: - res = nums[0] - l, r = 0, len(nums) - 1 - - while l <= r: - if nums[l] < nums[r]: - res = min(res, nums[l]) - break - m = (l + r) // 2 - res = min(res, nums[m]) - if nums[m] >= nums[l]: - l = m + 1 + left, right = 0, len(nums) - 1 + while left < right: + middle = (left + right) // 2 + if nums[middle] < nums[right]: + right = middle else: - r = m - 1 - return res + left = middle + 1 + return nums[left] From fe31636e846873d64ebf1a2bdf8cef20860a77ff Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 26 Aug 2022 11:58:42 -0400 Subject: [PATCH 02/57] #33 update --- python/33-Search-In-Rotated-Sorted-Array.py | 28 +++++++++------------ 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/python/33-Search-In-Rotated-Sorted-Array.py b/python/33-Search-In-Rotated-Sorted-Array.py index fe01019d4..a9c7b8d4d 100644 --- a/python/33-Search-In-Rotated-Sorted-Array.py +++ b/python/33-Search-In-Rotated-Sorted-Array.py @@ -1,22 +1,18 @@ class Solution: def search(self, nums: List[int], target: int) -> int: - l, r = 0, len(nums) - 1 - - while l <= r: - mid = (l + r) // 2 - if target == nums[mid]: + start, end = 0, len(nums) - 1 + while start <= end: + mid = start + (end - start) // 2 + if nums[mid] == target: return mid - - # left sorted portion - if nums[l] <= nums[mid]: - if target > nums[mid] or target < nums[l]: - l = mid + 1 + elif nums[mid] >= nums[start]: + if target >= nums[start] and target < nums[mid]: + end = mid - 1 else: - r = mid - 1 - # right sorted portion + start = mid + 1 else: - if target < nums[mid] or target > nums[r]: - r = mid - 1 + if target <= nums[end] and target > nums[mid]: + start = mid + 1 else: - l = mid + 1 - return -1 + end = mid - 1 + return -1 \ No newline at end of file From c9aef801b70185b1065aa2dc5912468467192739 Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 26 Aug 2022 13:09:55 -0400 Subject: [PATCH 03/57] #704 update --- python/704-Binary-Search.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/704-Binary-Search.py b/python/704-Binary-Search.py index df95ce190..5dc83448e 100644 --- a/python/704-Binary-Search.py +++ b/python/704-Binary-Search.py @@ -1,13 +1,13 @@ class Solution: def search(self, nums: List[int], target: int) -> int: - l, r = 0, len(nums) - 1 - - while l <= r: - m = l + ((r - l) // 2) # (l + r) // 2 can lead to overflow - if nums[m] > target: - r = m - 1 - elif nums[m] < target: - l = m + 1 + l,r=0, len(nums)-1 + while l<=r: + mid = (l+r) //2 + if nums[mid] ==target: + return mid + if nums[mid] < target: + l=mid+1 else: - return m + r=mid-1 return -1 + From 5c9eae665852871543d3f2f8ef09d85ea9875f1d Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 30 Aug 2022 13:43:45 -0400 Subject: [PATCH 04/57] #211 update --- ...ign-Add-and-Search-Words-Data-Structure.py | 100 +++++++++++++----- 1 file changed, 73 insertions(+), 27 deletions(-) diff --git a/python/211-Design-Add-and-Search-Words-Data-Structure.py b/python/211-Design-Add-and-Search-Words-Data-Structure.py index 3c5f562aa..e07dd8dd1 100644 --- a/python/211-Design-Add-and-Search-Words-Data-Structure.py +++ b/python/211-Design-Add-and-Search-Words-Data-Structure.py @@ -1,36 +1,82 @@ -class TrieNode: - def __init__(self): - self.children = {} # a : TrieNode - self.word = False - - class WordDictionary: + def __init__(self): - self.root = TrieNode() + """ + Initialize your data structure here. + """ + self.trie = {} + def addWord(self, word: str) -> None: - cur = self.root - for c in word: - if c not in cur.children: - cur.children[c] = TrieNode() - cur = cur.children[c] - cur.word = True + """ + Adds a word into the data structure. + """ + node = self.trie + + for ch in word: + if not ch in node: + node[ch] = {} + node = node[ch] + node['$'] = True def search(self, word: str) -> bool: - def dfs(j, root): - cur = root - - for i in range(j, len(word)): - c = word[i] - if c == ".": - for child in cur.children.values(): - if dfs(i + 1, child): - return True + """ + Returns if the word is in the data structure. A word could contain the dot character '.' to represent any letter. + """ + def search_in_node(word, node) -> bool: + for i, ch in enumerate(word): + if not ch in node: + # if the current character is '.' + # check all possible nodes at this level + if ch == '.': + for x in node: + if x != '$' and search_in_node(word[i + 1:], node[x]): + return True + # if no nodes lead to answer + # or the current character != '.' return False + # if the character is found + # go down to the next level in trie else: - if c not in cur.children: - return False - cur = cur.children[c] - return cur.word + node = node[ch] + return '$' in node + + return search_in_node(word, self.trie) + + + +#class WordNode: + #def __init__(self): + #self.children = {} + #self.isEnd = False + +#class WordDictionary: + #def __init__(self): + #self.root = WordNode() + + #def addWord(self, word): + #node = self.root + #for w in word: + #if w in node.children: + #node = node.children[w] + #else: + #node.children[w] = WordNode() + #node = node.children[w] + #node.isEnd = True - return dfs(0, self.root) + #def search(self, word): + #stack = [(self.root,word)] + #while stack: + #node, w = stack.pop() + #if not w: + #if node.isEnd: + #return True + #elif w[0]=='.': + #for n in node.children.values(): + #stack.append((n,w[1:])) + #else: + #if w[0] in node.children: + #n = node.children[w[0]] + #stack.append((n,w[1:])) + #return False + \ No newline at end of file From e5a50bd9532c033772218c1d6c9c7cdc1cc1bba3 Mon Sep 17 00:00:00 2001 From: Brian Date: Tue, 30 Aug 2022 23:51:31 -0400 Subject: [PATCH 05/57] #39 update --- python/39-Combination-Sum.py | 66 ++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/python/39-Combination-Sum.py b/python/39-Combination-Sum.py index 7df4c4b4f..9d5b22580 100644 --- a/python/39-Combination-Sum.py +++ b/python/39-Combination-Sum.py @@ -1,18 +1,62 @@ class Solution: def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: - res = [] - def dfs(i, cur, total): - if total == target: - res.append(cur.copy()) + results = [] + + def backtrack(remain, comb, start): + if remain == 0: + # make a deep copy of the current combination + results.append(list(comb)) return - if i >= len(candidates) or total > target: + elif remain < 0: + # exceed the scope, stop exploration. return - cur.append(candidates[i]) - dfs(i, cur, total + candidates[i]) - cur.pop() - dfs(i + 1, cur, total) + for i in range(start, len(candidates)): + # add the number into the combination + comb.append(candidates[i]) + # give the current number another chance, rather than moving on + backtrack(remain - candidates[i], comb, i) + # backtrack, remove the number from the combination + comb.pop() + + backtrack(target, [], 0) + + return results + + + +#class Solution(object): + #def combinationSum(self, candidates, target): + #res = [] + + #def dfs(nums, target, path): + #if target < 0: + #return + #if target == 0: + #res.append(path) + #return + #for i in range(len(nums)): + #dfs(nums[i:], target-nums[i], path+[nums[i]]) + #dfs(candidates, target, []) + #return res + + +#class Solution: + #def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]: + #res = [] + + #def dfs(i, cur, total): + #if total == target: + #res.append(cur.copy()) + #return + #if i >= len(candidates) or total > target: + #return + + #cur.append(candidates[i]) + #dfs(i, cur, total + candidates[i]) + #cur.pop() + #dfs(i + 1, cur, total) - dfs(0, [], 0) - return res + #dfs(0, [], 0) + #return res From a885ca4bc39896a551435140e82cebc5096f365a Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 4 Sep 2022 21:12:32 -0400 Subject: [PATCH 06/57] #91 update --- python/91-Decode-ways.py | 48 ++++++++++++++-------------------------- 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/python/91-Decode-ways.py b/python/91-Decode-ways.py index f5b4b5ada..4c2aa0379 100644 --- a/python/91-Decode-ways.py +++ b/python/91-Decode-ways.py @@ -1,34 +1,18 @@ class Solution: def numDecodings(self, s: str) -> int: - # Memoization - dp = {len(s): 1} - - def dfs(i): - if i in dp: - return dp[i] - if s[i] == "0": - return 0 - - res = dfs(i + 1) - if i + 1 < len(s) and ( - s[i] == "1" or s[i] == "2" and s[i + 1] in "0123456" - ): - res += dfs(i + 2) - dp[i] = res - return res - - return dfs(0) - - # Dynamic Programming - dp = {len(s): 1} - for i in range(len(s) - 1, -1, -1): - if s[i] == "0": - dp[i] = 0 - else: - dp[i] = dp[i + 1] - - if i + 1 < len(s) and ( - s[i] == "1" or s[i] == "2" and s[i + 1] in "0123456" - ): - dp[i] += dp[i + 2] - return dp[0] + if s[0] == "0": + return 0 + + first = 1 + second = 1 + for i in range(1, len(s)): + current = 0 + if s[i] != "0": + current = second + two_digit = int(s[i - 1: i + 1]) + if two_digit >= 10 and two_digit <= 26: + current += first + first = second + second = current + + return second \ No newline at end of file From a4d9cc332184ae41ce948ef595b9418220ea364f Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Sep 2022 12:11:46 -0400 Subject: [PATCH 07/57] #875 update --- python/875-Koko-Eating-Bananas.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/python/875-Koko-Eating-Bananas.py b/python/875-Koko-Eating-Bananas.py index e4a730343..65b2e86b8 100644 --- a/python/875-Koko-Eating-Bananas.py +++ b/python/875-Koko-Eating-Bananas.py @@ -1,17 +1,19 @@ class Solution: def minEatingSpeed(self, piles: List[int], h: int) -> int: - l, r = 1, max(piles) - k = 0 + def calcHours(k): + sum=0 + for pile in piles: + sum += math.ceil(pile/k) + return sum - while l <= r: - m = (l + r) // 2 - totalTime = 0 - for p in piles: - totalTime += ((p - 1) // m) + 1 - if totalTime <= h: - k = m - r = m - 1 + l,r =1, max(piles) + answer=r + while l<=r: + m= l+(r-l)//2 + if calcHours(m) > h: + l=m+1 else: - l = m + 1 - return k + answer=m + r=m-1 + return answer From e8c53d22335a52e63e7325d795716eb214aee1b8 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Sep 2022 12:20:40 -0400 Subject: [PATCH 08/57] #518 update --- python/518-coin-change-2.py | 48 ++++--------------------------------- 1 file changed, 4 insertions(+), 44 deletions(-) diff --git a/python/518-coin-change-2.py b/python/518-coin-change-2.py index 163d2d06e..b4c2187fc 100644 --- a/python/518-coin-change-2.py +++ b/python/518-coin-change-2.py @@ -1,49 +1,9 @@ class Solution: def change(self, amount: int, coins: List[int]) -> int: - # MEMOIZATION - # Time: O(n*m) - # Memory: O(n*m) - cache = {} - - def dfs(i, a): - if a == amount: - return 1 - if a > amount: - return 0 - if i == len(coins): - return 0 - if (i, a) in cache: - return cache[(i, a)] - - cache[(i, a)] = dfs(i, a + coins[i]) + dfs(i + 1, a) - return cache[(i, a)] - - return dfs(0, 0) - - # DYNAMIC PROGRAMMING - # Time: O(n*m) - # Memory: O(n*m) - dp = [[0] * (len(coins) + 1) for i in range(amount + 1)] - dp[0] = [1] * (len(coins) + 1) - for a in range(1, amount + 1): - for i in range(len(coins) - 1, -1, -1): - dp[a][i] = dp[a][i + 1] - if a - coins[i] >= 0: - dp[a][i] += dp[a - coins[i]][i] - return dp[amount][0] - - # DYNAMIC PROGRAMMING - # Time: O(n*m) - # Memory: O(n) where n = amount dp = [0] * (amount + 1) dp[0] = 1 - for i in range(len(coins) - 1, -1, -1): - nextDP = [0] * (amount + 1) - nextDP[0] = 1 - for a in range(1, amount + 1): - nextDP[a] = dp[a] - if a - coins[i] >= 0: - nextDP[a] += nextDP[a - coins[i]] - dp = nextDP - return dp[amount] + for coin in coins: + for x in range(coin, amount + 1): + dp[x] += dp[x - coin] + return dp[amount] \ No newline at end of file From 05c8f7836a75440b168d9914d038f7b179effc7d Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Sep 2022 12:25:05 -0400 Subject: [PATCH 09/57] #983 added --- python/983-Min-Cost-For-Tickets.py | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 python/983-Min-Cost-For-Tickets.py diff --git a/python/983-Min-Cost-For-Tickets.py b/python/983-Min-Cost-For-Tickets.py new file mode 100644 index 000000000..0e7800696 --- /dev/null +++ b/python/983-Min-Cost-For-Tickets.py @@ -0,0 +1,11 @@ +class Solution: + def mincostTickets(self, days: List[int], costs: List[int]) -> int: + + dp = [0]*(days[-1]+1) + days = set(days) + for i in range(1,len(dp)): + if i in days: + dp[i] = min(dp[max(i-1,0)]+costs[0],dp[max(i-7,0)]+costs[1],dp[max(i-30,0)]+costs[2]) + else: + dp[i]=dp[i-1] + return dp[-1] From c3fb205e1d626246dc484c1b898e8c51b6f3261e Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 8 Sep 2022 15:22:01 -0400 Subject: [PATCH 10/57] #33 update --- python/33-Search-In-Rotated-Sorted-Array.py | 31 +++++++++++---------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/python/33-Search-In-Rotated-Sorted-Array.py b/python/33-Search-In-Rotated-Sorted-Array.py index a9c7b8d4d..65f509555 100644 --- a/python/33-Search-In-Rotated-Sorted-Array.py +++ b/python/33-Search-In-Rotated-Sorted-Array.py @@ -1,18 +1,21 @@ class Solution: def search(self, nums: List[int], target: int) -> int: - start, end = 0, len(nums) - 1 - while start <= end: - mid = start + (end - start) // 2 - if nums[mid] == target: - return mid - elif nums[mid] >= nums[start]: - if target >= nums[start] and target < nums[mid]: - end = mid - 1 + l,r=0,len(nums)-1 + while l<=r: + #[5] + m = l + (r-l)//2 + if nums[m] == target: + return m + elif nums[r] >= nums[m]: + if nums[m]< target and target <= nums[r]: + l=m+1 else: - start = mid + 1 - else: - if target <= nums[end] and target > nums[mid]: - start = mid + 1 + r=m-1 + elif nums[l] <= nums[m]: + if nums[m] > target and target >=nums[l]: + r=m-1 else: - end = mid - 1 - return -1 \ No newline at end of file + l=m+1 + + return -1 + From b83a7c7c73911685865028ceec3d75220cd96fe4 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 11 Sep 2022 16:04:41 -0400 Subject: [PATCH 11/57] #143 re-update --- python/143-Reorder-List.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/python/143-Reorder-List.py b/python/143-Reorder-List.py index 899ae98a0..6d0703dcf 100644 --- a/python/143-Reorder-List.py +++ b/python/143-Reorder-List.py @@ -2,6 +2,8 @@ class Solution: def reorderList(self, head: ListNode) -> None: # find middle slow, fast = head, head.next + #following will also work + #slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next From a36f53765013ea30f723f62b4c8e27b172fbe9d8 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 11 Sep 2022 19:31:12 -0400 Subject: [PATCH 12/57] #226 update --- python/226-Invert-Binary-Tree.py | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/python/226-Invert-Binary-Tree.py b/python/226-Invert-Binary-Tree.py index 71740bd12..89dc70c46 100644 --- a/python/226-Invert-Binary-Tree.py +++ b/python/226-Invert-Binary-Tree.py @@ -5,15 +5,8 @@ # self.left = left # self.right = right class Solution: - def invertTree(self, root: TreeNode) -> TreeNode: + def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]: if not root: - return None - - # swap the children - tmp = root.left - root.left = root.right - root.right = tmp - - self.invertTree(root.left) - self.invertTree(root.right) + return None + root.left,root.right =self.invertTree(root.right), self.invertTree(root.left) return root From d017cf28e3f2496813d48e892db4902609d1033f Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 10 Aug 2023 22:48:02 +0100 Subject: [PATCH 13/57] #424 update --- python/424-Longest-Repeating-Character-Replacement.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/python/424-Longest-Repeating-Character-Replacement.py b/python/424-Longest-Repeating-Character-Replacement.py index 7c6864cdc..fa1501ac9 100644 --- a/python/424-Longest-Repeating-Character-Replacement.py +++ b/python/424-Longest-Repeating-Character-Replacement.py @@ -4,12 +4,10 @@ def characterReplacement(self, s: str, k: int) -> int: res = 0 l = 0 - maxf = 0 for r in range(len(s)): count[s[r]] = 1 + count.get(s[r], 0) - maxf = max(maxf, count[s[r]]) - if (r - l + 1) - maxf > k: + while (r - l + 1) - max(count.values()) > k: count[s[l]] -= 1 l += 1 From bc060587f00b89e89b65cce3f42a3aca978f4278 Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 11 Aug 2023 14:29:28 +0100 Subject: [PATCH 14/57] #20 update --- python/20-Valid-Parentheses.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/python/20-Valid-Parentheses.py b/python/20-Valid-Parentheses.py index 4d0ae3424..c77771dad 100644 --- a/python/20-Valid-Parentheses.py +++ b/python/20-Valid-Parentheses.py @@ -1,14 +1,12 @@ class Solution: def isValid(self, s: str) -> bool: - Map = {")": "(", "]": "[", "}": "{"} stack = [] - - for c in s: - if c not in Map: - stack.append(c) - continue - if not stack or stack[-1] != Map[c]: - return False - stack.pop() - - return not stack + mapping = {'}':'{', ']':'[', ')':'('} + for letter in s: + if letter in mapping: + if not stack or stack.pop() != mapping[letter]: + return False + else: + stack.append(letter) + if not stack: + return True \ No newline at end of file From 7a477b48035b98c570a3beeb4e3b723b942b9fc2 Mon Sep 17 00:00:00 2001 From: Brian Date: Fri, 11 Aug 2023 19:30:26 +0100 Subject: [PATCH 15/57] #74 update --- python/74-Search-a-2D-Matrix.py | 38 +++++++++++++++------------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/python/74-Search-a-2D-Matrix.py b/python/74-Search-a-2D-Matrix.py index 8f986dc25..b16d0ad1b 100644 --- a/python/74-Search-a-2D-Matrix.py +++ b/python/74-Search-a-2D-Matrix.py @@ -1,27 +1,23 @@ class Solution: def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: - ROWS, COLS = len(matrix), len(matrix[0]) + rows, cols = len(matrix), len(matrix[0]) - top, bot = 0, ROWS - 1 - while top <= bot: - row = (top + bot) // 2 - if target > matrix[row][-1]: - top = row + 1 - elif target < matrix[row][0]: - bot = row - 1 + up,down= 0, rows-1 + while up<=down: + mid = up + (down-up)//2 + if target < matrix[mid][0]: + down = mid-1 + elif target> matrix[mid][-1]: + up = mid+1 else: break - - if not (top <= bot): - return False - row = (top + bot) // 2 - l, r = 0, COLS - 1 - while l <= r: - m = (l + r) // 2 - if target > matrix[row][m]: - l = m + 1 - elif target < matrix[row][m]: - r = m - 1 - else: + l,r = 0, cols-1 + while l<=r: + m = l+(r-l)//2 + if target == matrix[mid][m]: return True - return False + elif target > matrix[mid][m]: + l= m+1 + else: + r=m-1 + return False \ No newline at end of file From eff87ad32a1bb4e44f857f3c0ae0f3a392b2a172 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 12 Aug 2023 21:38:40 +0100 Subject: [PATCH 16/57] #238 update --- python/238-Product-of-array-except-self.py | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/python/238-Product-of-array-except-self.py b/python/238-Product-of-array-except-self.py index 0326913a3..634cff3c2 100644 --- a/python/238-Product-of-array-except-self.py +++ b/python/238-Product-of-array-except-self.py @@ -1,13 +1,11 @@ class Solution: def productExceptSelf(self, nums: List[int]) -> List[int]: - res = [1] * (len(nums)) - - prefix = 1 - for i in range(len(nums)): - res[i] = prefix - prefix *= nums[i] - postfix = 1 - for i in range(len(nums) - 1, -1, -1): - res[i] *= postfix - postfix *= nums[i] - return res + + output = [1] * len(nums) + for i in range(len(nums)-1): + output[i+1] = nums[i] * output[i] + mult =1 + for j in reversed(range(len(nums)-1)): + mult *= nums[j+1] + output[j] *= mult + return output \ No newline at end of file From a82d52a92b435aa5b1058f835e9ad64be93d3c3b Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 12 Aug 2023 21:49:47 +0100 Subject: [PATCH 17/57] #271 update --- python/271-Encode-and-Decode-Strings.py | 54 ++++++++++++------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/python/271-Encode-and-Decode-Strings.py b/python/271-Encode-and-Decode-Strings.py index 722f440d7..03431ea53 100644 --- a/python/271-Encode-and-Decode-Strings.py +++ b/python/271-Encode-and-Decode-Strings.py @@ -1,28 +1,28 @@ -class Solution: - """ - @param: strs: a list of strings - @return: encodes a list of strings to a single string. - """ +class Codec: + def encode(self, strs: List[str]) -> str: + """Encodes a list of strings to a single string. + """ + encoded = '' + for string in strs: + encoded= encoded+ str(len(string)) + '#'+ string + #encoded = chr(258).join(strs) + return encoded + + - def encode(self, strs): - res = "" - for s in strs: - res += str(len(s)) + "#" + s - return res - - """ - @param: str: A string - @return: dcodes a single string to a list of strings - """ - - def decode(self, str): - res, i = [], 0 - - while i < len(str): - j = i - while str[j] != "#": - j += 1 - length = int(str[i:j]) - res.append(str[j + 1 : j + 1 + length]) - i = j + 1 + length - return res + def decode(self, s: str) -> List[str]: + """Decodes a single string to a list of strings. + """ + i = 0 + last_start = 0 + decoded=[] + while i < len(s): + if s[i] == '#': + length = int(s[last_start:i]) + decoded.append(s[i+1:i+length+1]) + last_start = i+length+1 + i +=length+1 + else: + i +=1 + #decoded = s.split(sep= chr(258)) + return decoded \ No newline at end of file From 322cecfd59dd84ad59b1cbb5441cdc341832e634 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 19 Aug 2023 20:53:47 +0100 Subject: [PATCH 18/57] #104 minor update --- python/104-Maximum-Depth-of-Binary-Tree.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/104-Maximum-Depth-of-Binary-Tree.py b/python/104-Maximum-Depth-of-Binary-Tree.py index ac919b7a0..008ae7cdf 100644 --- a/python/104-Maximum-Depth-of-Binary-Tree.py +++ b/python/104-Maximum-Depth-of-Binary-Tree.py @@ -7,7 +7,7 @@ def maxDepth(self, root: TreeNode) -> int: return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) -# ITERATIVE DFS +# ITERATIVE PREORDER DFS class Solution: def maxDepth(self, root: TreeNode) -> int: stack = [[root, 1]] From 8df043ae98913da8995f459891d9da5aa062832a Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 19 Aug 2023 21:26:02 +0100 Subject: [PATCH 19/57] #100 minor update --- python/100-Same-Tree.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/100-Same-Tree.py b/python/100-Same-Tree.py index 4d55e2588..2e63cb29e 100644 --- a/python/100-Same-Tree.py +++ b/python/100-Same-Tree.py @@ -5,7 +5,19 @@ # self.left = None # self.right = None +#solution 1 +class Solution: + def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: + if not p and not q: + return True + + if not p or not q or p.val != q.va: + return False + return self.isSameTree(p.left, q.left) and self.isSameTree(p.right, q.right) + + +#solution 2 class Solution: def isSameTree(self, p: TreeNode, q: TreeNode) -> bool: if not p and not q: From 8ae925b03a3736d4c2cf716df212f74710ee0b8e Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 24 Aug 2023 12:30:29 +0100 Subject: [PATCH 20/57] #70 update --- python/70-Climbing-Stairs.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/70-Climbing-Stairs.py b/python/70-Climbing-Stairs.py index e41decaba..d07bb9d21 100644 --- a/python/70-Climbing-Stairs.py +++ b/python/70-Climbing-Stairs.py @@ -1,3 +1,20 @@ +class Solution: + def climbStairs(self, n: int) -> int: + first, second= 0,1 + for i in range(n): + first, second= second, first+second + return second + +class Solution: + def climbStairs(self, n: int) -> int: + hashmap={-1:0,0:1} + def helper(n): + if n not in hashmap: + hashmap[n]=helper(n-1)+helper(n-2) + return hashmap[n] + return helper(n) + + class Solution: def climbStairs(self, n: int) -> int: if n <= 3: From bf5dc0e6f74b8690c7d9254e9a791a6d9701182b Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 24 Aug 2023 12:30:43 +0100 Subject: [PATCH 21/57] #746 update --- python/746-Min-Cost-Climbing-Stairs.py | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/python/746-Min-Cost-Climbing-Stairs.py b/python/746-Min-Cost-Climbing-Stairs.py index 0f0bc0bde..e2e2898d5 100644 --- a/python/746-Min-Cost-Climbing-Stairs.py +++ b/python/746-Min-Cost-Climbing-Stairs.py @@ -1,3 +1,32 @@ +#buttomup dp +class Solution: + def minCostClimbingStairs(self, cost: List[int]) -> int: + first,second=0,0 + for i in range(2,len(cost)+1): + first, second=second,min(first+cost[i-2],second+cost[i-1]) + return second +#recursive top down with memoization +class Solution: + def minCostClimbingStairs(self, cost: List[int]) -> int: + hashmap={0:0,1:0} + def helper(n): + if n not in hashmap: + hashmap[n]= min(helper(n-2)+cost[n-2], helper(n-1)+cost[n-1]) + return hashmap[n] + return helper(len(cost)) + +#recursive with lru-cache +from functools import lru_cache +class Solution: + def minCostClimbingStairs(self, cost: List[int]) -> int: + #we cannot pass a list to function with lru_cache, so a helper function is used + @lru_cache + def helper(n): + if n==0 or n==1: + return 0 + return min(helper(n-2)+cost[n-2], helper(n-1)+cost[n-1]) + return helper(len(cost)) + class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: for i in range(len(cost) - 3, -1, -1): From 8bc1782faa96cd30a28d77250bcff337df30a569 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 24 Aug 2023 12:30:52 +0100 Subject: [PATCH 22/57] #198 update --- python/198-House-Robber.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/python/198-House-Robber.py b/python/198-House-Robber.py index 512f67aea..904c94f4e 100644 --- a/python/198-House-Robber.py +++ b/python/198-House-Robber.py @@ -1,3 +1,39 @@ +class Solution: + def rob(self, nums: List[int]) -> int: + first,second=0,0 + for i in range(len(nums)): + first,second=second, max(first+nums[i],second) + return second + + +class Solution: + def rob(self, nums: List[int]) -> int: + hashmap={-1:0,-2:0} + def helper(n): + if n not in hashmap: + hashmap[n]=max(nums[n]+helper(n-2), helper(n-1)) + return hashmap[n] + return helper(len(nums)-1) + +class Solution: + def rob(self, nums: List[int]) -> int: + # edge cases: + if len(nums) == 0: return 0 + if len(nums) == 1: return nums[0] + if len(nums) == 2: return max(nums) + + # dynamic programming - decide each problem by its sub-problems: + dp = [0]*len(nums) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + for i in range(2, len(nums)): + dp[i] = max(dp[i-1], nums[i]+dp[i-2]) + + return dp[-1] + + + + class Solution: def rob(self, nums: List[int]) -> int: rob1, rob2 = 0, 0 From 9d7bec95f7de136f542f1362248d761dbaddbd97 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:32:15 +0100 Subject: [PATCH 23/57] #1143 update --- python/1143-Longest-Common-Subsequence.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/python/1143-Longest-Common-Subsequence.py b/python/1143-Longest-Common-Subsequence.py index 0860720a5..29585e981 100644 --- a/python/1143-Longest-Common-Subsequence.py +++ b/python/1143-Longest-Common-Subsequence.py @@ -1,3 +1,22 @@ +class Solution: + def longestCommonSubsequence(self, s1: str, s2: str) -> int: + m = len(s1) + n = len(s2) + memo = [[0 for _ in range(n + 1)] for _ in range(m + 1)] + + for row in range(1, m + 1): + for col in range(1, n + 1): + if s1[row - 1] == s2[col - 1]: + memo[row][col] = 1 + memo[row - 1][col - 1] + else: + memo[row][col] = max(memo[row][col - 1], memo[row - 1][col]) + + return memo[m][n] + + + + + class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: dp = [[0 for j in range(len(text2) + 1)] for i in range(len(text1) + 1)] From f8f4562aad414416223b199ae0797b82038dbe81 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:32:34 +0100 Subject: [PATCH 24/57] #139 update --- python/139-Word-Break.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/python/139-Word-Break.py b/python/139-Word-Break.py index 681107bd2..75bba2e79 100644 --- a/python/139-Word-Break.py +++ b/python/139-Word-Break.py @@ -1,3 +1,22 @@ +#bottom up dynamic programming +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + dp = [False] * len(s) + for i in range(len(s)): + for word in wordDict: + # Handle out of bounds case + if i < len(word) - 1: + continue + + if i == len(word) - 1 or dp[i - len(word)]: + if s[i - len(word) + 1:i + 1] == word: + dp[i] = True + break + + return dp[-1] + + + class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool: From b13dc4ddb3f677f9140dabd66707824afa29ce42 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:32:50 +0100 Subject: [PATCH 25/57] #300 update --- python/300-Longest-Increasing-Subsequence.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/python/300-Longest-Increasing-Subsequence.py b/python/300-Longest-Increasing-Subsequence.py index 854767039..674925cab 100644 --- a/python/300-Longest-Increasing-Subsequence.py +++ b/python/300-Longest-Increasing-Subsequence.py @@ -1,3 +1,14 @@ +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + dp = [1] * len(nums) + for i in range(1, len(nums)): + for j in range(i): + if nums[i] > nums[j]: + dp[i] = max(dp[i], dp[j] + 1) + + return max(dp) + + class Solution: def lengthOfLIS(self, nums: List[int]) -> int: LIS = [1] * len(nums) From c8caf23e3f54ca281f76850c1cf29970bc8f18ae Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:33:01 +0100 Subject: [PATCH 26/57] #494 update --- python/494-Target-Sum.py | 45 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/python/494-Target-Sum.py b/python/494-Target-Sum.py index e8965ecba..1ba8ab6aa 100644 --- a/python/494-Target-Sum.py +++ b/python/494-Target-Sum.py @@ -1,3 +1,48 @@ +class Solution: + def findTargetSumWays(self, nums: List[int], S: int) -> int: + + ## RC ## + ## APPROACH : DP ## + ## INTUITION : THINK LIKE SUBSET SUM PROBLEM (tushor roy DP solution) Leetcode 416. Partition equal subset sum ## + # but here 1. our target can range from -totalSum to +totalSum + # 2. and we dont include True directly from above sequence, coz it is not subsequence we are looking for. so here consider if and only if previous value exists + # [1,1,1,1,1] + # 3 + # [ + # [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0], + # [0, 0, 0, 1, 0, 2, 0, 1, 0, 0, 0], + # [0, 0, 1, 0, 3, 0, 3, 0, 1, 0, 0], + # [0, 1, 0, 4, 0, 6, 0, 4, 0, 1, 0], + # [1, 0, 5, 0, 10, 0, 10, 0, 5, 0, 1] + # ] + + ## TIME COMPLEXITY : O(N^2) ## + ## SPACE COMPLEXITY : O(N^2) ## + + totalSum = sum(nums) + if(S not in range(-1 * totalSum, totalSum + 1) ): return 0 + dp = [ [ 0 for j in range( totalSum*2 + 1 ) ] for i in range(len(nums))] + + ## BASE CASE ## FIRST ROW ## + dp[0][totalSum + nums[0]] += 1 + dp[0][totalSum - nums[0]] += 1 + + for i in range(1, len(nums)): + for j in range( totalSum*2 + 1 ): + + if( j - nums[i] >= 0 and dp[i-1][j-nums[i]] > 0 ): # left side + dp[i][j] += dp[i-1][j-nums[i]] + + if( j + nums[i] <= totalSum*2 and dp[i-1][j+nums[i]] > 0 ): # right side + dp[i][j] += dp[i-1][j+nums[i]] + + print(dp) + return dp[-1][totalSum + S] + + + + + class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: dp = {} # (index, total) -> # of ways From d844a90f9331b4fbff5ca62a6a604341c16984b0 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:33:13 +0100 Subject: [PATCH 27/57] #518 update --- python/518-coin-change-2.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/python/518-coin-change-2.py b/python/518-coin-change-2.py index b4c2187fc..8c3914d1d 100644 --- a/python/518-coin-change-2.py +++ b/python/518-coin-change-2.py @@ -1,3 +1,35 @@ +#bottom up 2D dp +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + dp = [[0 for _ in range(amount+1)] for _ in range(len(coins))] + + for row in range(len(coins)): + dp[row][0] = 1 + for row in range(len(coins)): + for col in range(1, amount+1): + if coins[row] > col: + dp[row][col] = dp[row-1][col] + else: + dp[row][col] = dp[row-1][col] + dp[row][col-coins[row]] + return dp[-1][-1] + +#if we wanted to add a first row of 0s, then row-1 would corespond to coins index +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + + n = len(coins) + M = [[0 for i in range(amount+1)] for x in range(n+1)] + for i in range(n+1): + M[i][0] = 1 + for i in range(1, n+1): + for j in range(1, amount+1): + if coins[i-1] > j: + M[i][j] = M[i-1][j] + else: + M[i][j] = M[i-1][j] + M[i][j-coins[i-1]] + return M[n][amount] + + class Solution: def change(self, amount: int, coins: List[int]) -> int: dp = [0] * (amount + 1) From 078887aa7cdd677195ddae99b4f3dfba8a7a661c Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:33:24 +0100 Subject: [PATCH 28/57] #62 update --- python/62-Unique-Paths.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/62-Unique-Paths.py b/python/62-Unique-Paths.py index c5c418de6..fb2173b62 100644 --- a/python/62-Unique-Paths.py +++ b/python/62-Unique-Paths.py @@ -1,3 +1,17 @@ +#bottom up dynamic programming +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + d = [[1] * n for _ in range(m)] + + for row in range(1, m): + for col in range(1, n): + d[row][col] = d[row - 1][col] + d[row][col - 1] + + return d[m - 1][n - 1] + + + + class Solution: def uniquePaths(self, m: int, n: int) -> int: row = [1] * n From 943e3fef63d85f88be655f483c4b349f8c6dbfde Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:33:36 +0100 Subject: [PATCH 29/57] #91 update --- python/91-Decode-ways.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/python/91-Decode-ways.py b/python/91-Decode-ways.py index 4c2aa0379..d3078ae0b 100644 --- a/python/91-Decode-ways.py +++ b/python/91-Decode-ways.py @@ -1,3 +1,20 @@ +#best solution - iterative bottom up +class Solution: + def numDecodings(self, s: str) -> int: + first, second=0,1 + + for i in range(len(s)): + temp_sum=0 + temp=second + if int(s[i]) >0 and int(s[i])<=9: + temp_sum+=second + if i>0 and int(s[i-1:i+1]) >=10 and int(s[i-1:i+1])<=26: + temp_sum+=first + second=temp_sum + first=temp + return second + + class Solution: def numDecodings(self, s: str) -> int: if s[0] == "0": From f219cc410e7e2e7d0527ba04a52f3e1069bf7762 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 27 Aug 2023 21:33:48 +0100 Subject: [PATCH 30/57] #97 update --- python/97-Interleaving-Strings.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/python/97-Interleaving-Strings.py b/python/97-Interleaving-Strings.py index efb43ac60..62a98c8fe 100644 --- a/python/97-Interleaving-Strings.py +++ b/python/97-Interleaving-Strings.py @@ -1,3 +1,27 @@ +class Solution: + def isInterleave(self, s1: str, s2: str, s3: str) -> bool: + m, n, l = len(s1), len(s2), len(s3) + if m + n != l: + return False + + dp = [[False] * (n + 1) for _ in range(m + 1)] + dp[0][0] = True + + for i in range(1, m + 1): + dp[i][0] = dp[i-1][0] and s1[i-1] == s3[i-1] + + for j in range(1, n + 1): + dp[0][j] = dp[0][j-1] and s2[j-1] == s3[j-1] + + for i in range(1, m + 1): + for j in range(1, n + 1): + dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and s2[j-1] == s3[i+j-1]) + + return dp[m][n] + + + + class Solution: def isInterleave(self, s1: str, s2: str, s3: str) -> bool: if len(s1) + len(s2) != len(s3): From d4f0a10fb8de48612b1ecad445b2a081002035d4 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 28 Aug 2023 19:18:52 +0100 Subject: [PATCH 31/57] #72 update --- python/72-Edit-Distance.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/python/72-Edit-Distance.py b/python/72-Edit-Distance.py index 68c05d699..d26fa4681 100644 --- a/python/72-Edit-Distance.py +++ b/python/72-Edit-Distance.py @@ -1,3 +1,27 @@ +#bottom up 2D dp +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + m = len(word1) + n = len(word2) + # dp[i][j] := min # Of operations to convert word1[0..i) to word2[0..j) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + for i in range(1, m + 1): + dp[i][0] = i + + for j in range(1, n + 1): + dp[0][j] = j + + for i in range(1, m + 1): + for j in range(1, n + 1): + if word1[i - 1] == word2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + else: + dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 + + return dp[m][n] + + class Solution: def minDistance(self, word1: str, word2: str) -> int: dp = [[float("inf")] * (len(word2) + 1) for i in range(len(word1) + 1)] From 1dafd28ff264e1ee61a0f7a7a6b0d267fb780b48 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 28 Aug 2023 19:19:04 +0100 Subject: [PATCH 32/57] #416 update --- python/416-Partition-Equal-Subset-Sum.py | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/python/416-Partition-Equal-Subset-Sum.py b/python/416-Partition-Equal-Subset-Sum.py index 0fa35c087..0e90e9ee5 100644 --- a/python/416-Partition-Equal-Subset-Sum.py +++ b/python/416-Partition-Equal-Subset-Sum.py @@ -1,3 +1,28 @@ +#bottom up dp, also the next solution OK +class Solution: + def canPartition(self, nums: List[int]) -> bool: + # find sum of array elements + total_sum = sum(nums) + + # if total_sum is odd, it cannot be partitioned into equal sum subsets + if total_sum % 2 != 0: + return False + subset_sum = total_sum // 2 + n = len(nums) + + # construct a dp table of size (n+1) x (subset_sum + 1) + dp = [[False] * (subset_sum + 1) for _ in range(n + 1)] + dp[0][0] = True + for i in range(1, n + 1): + curr = nums[i - 1] + for j in range(subset_sum + 1): + if j < curr: + dp[i][j] = dp[i - 1][j] + else: + dp[i][j] = dp[i - 1][j] or dp[i - 1][j - curr] + return dp[n][subset_sum] + + class Solution: def canPartition(self, nums: List[int]) -> bool: if sum(nums) % 2: From 26778052de02843e1b5390ac716618fb3f6d6ef4 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 28 Aug 2023 19:19:15 +0100 Subject: [PATCH 33/57] #312 update --- python/312-Burst-Balloons.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/python/312-Burst-Balloons.py b/python/312-Burst-Balloons.py index 0c19c6537..423d42760 100644 --- a/python/312-Burst-Balloons.py +++ b/python/312-Burst-Balloons.py @@ -1,3 +1,35 @@ +#2D dp (or 3D) reverse row, column +class Solution: + def maxCoins(self, nums: List[int]) -> int: + # special case + if len(nums) > 1 and len(set(nums)) == 1: + return (nums[0] ** 3) * (len(nums) - 2) + nums[0] ** 2 + nums[0] + + # handle edge case + nums = [1] + nums + [1] + n = len(nums) + # dp[i][j] represents + # maximum if we burst all nums[left]...nums[right], inclusive + dp = [[0] * n for _ in range(n)] + + # do not include the first one and the last one + # since they are both fake balloons added by ourselves and we can not + # burst them + for left in range(n - 2, 0, -1): + for right in range(left, n - 1): + # find the last burst one in nums[left]...nums[right] + for i in range(left, right + 1): + # nums[i] is the last burst one + gain = nums[left - 1] * nums[i] * nums[right + 1] + # recursively call left side and right side + remaining = dp[left][i - 1] + dp[i + 1][right] + # update + dp[left][right] = max(remaining + gain, dp[left][right]) + # burst nums[1]...nums[n-2], excluding the first one and the last one + return dp[1][n - 2] + + + class Solution: def maxCoins(self, nums: List[int]) -> int: cache = {} From 67608fd6a88f3545b1b8d2f371397b47604ef2e4 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 28 Aug 2023 19:19:27 +0100 Subject: [PATCH 34/57] #115 update --- python/115-Distinct-Subsequences.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/python/115-Distinct-Subsequences.py b/python/115-Distinct-Subsequences.py index 8f768fbfe..b6df28ba0 100644 --- a/python/115-Distinct-Subsequences.py +++ b/python/115-Distinct-Subsequences.py @@ -1,3 +1,26 @@ +class Solution: + def numDistinct(self, s: str, t: str) -> int: + m = len(s) + n = len(t) + dp = [[0] * (n+1) for _ in range(m+1)] + + for i in range(m+1): + dp[i][0] = 1 + + """redundant, as we have initialised dp table with full of zeros""" +# for i in range(1, n+1): +# dp[0][i] = 0 + + for i in range(1, m+1): + for j in range(1, n+1): + dp[i][j] += dp[i-1][j] #if current character is skipped + if s[i-1] == t[j-1]: + dp[i][j] += dp[i-1][j-1] #if current character is used + + return dp[-1][-1] + + + class Solution: def numDistinct(self, s: str, t: str) -> int: cache = {} From 1b6202126ed7649738df688288af2f9f741811bb Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 28 Aug 2023 19:19:47 +0100 Subject: [PATCH 35/57] #10 upadte --- python/10-Regular-Expression-Matching.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/python/10-Regular-Expression-Matching.py b/python/10-Regular-Expression-Matching.py index db8ad0a4c..06dc1c784 100644 --- a/python/10-Regular-Expression-Matching.py +++ b/python/10-Regular-Expression-Matching.py @@ -1,3 +1,23 @@ +#bottom up 2D dp +class Solution: + def isMatch(self, s, p): + dp = [[False] * (len(s) + 1) for _ in range(len(p) + 1)] + dp[0][0] = True + for i in range(2, len(p)): + dp[i][0] = dp[i - 2][0] and p[i-1] == '*' + for i in range(1, len(p)+1): + for j in range(1,len(s)+1): + if p[i-1] == '*': + dp[i][j] = dp[i - 2][j] or dp[i-1][j] + if p[i - 2] == s[j-1] or p[i - 2] == '.': + dp[i][j] |= dp[i][j-1] + else: + dp[i][j] = dp[i-1][j-1] and (p[i-1] == s[j-1] or p[i-1] == '.') + return dp[-1][-1] + + + + # BOTTOM-UP Dynamic Programming class Solution: def isMatch(self, s: str, p: str) -> bool: From 232db601974383119a4577a2a75399b2fd251d6f Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 14:21:33 +0100 Subject: [PATCH 36/57] #518 update --- ...ime-To-Buy-and-Sell-Stock-With-Cooldown.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py index c95b42883..7c838a09b 100644 --- a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py +++ b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py @@ -1,3 +1,27 @@ +#state machine & 1D dp +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + sold, held, reset = float('-inf'), float('-inf'), 0 + + for price in prices: + # Alternative: the calculation is done in parallel. + # Therefore no need to keep temporary variables + #sold, held, reset = held + price, max(held, reset-price), max(reset, sold) + + pre_sold = sold + sold = held + price + held = max(held, reset - price) + reset = max(reset, pre_sold) + + return max(sold, reset) + + + + class Solution: def maxProfit(self, prices: List[int]) -> int: # State: Buying or Selling? From 650a72720c433cd338e4ee49853c3b0c3954a78f Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 14:23:23 +0100 Subject: [PATCH 37/57] Revert "#518 update" This reverts commit 232db601974383119a4577a2a75399b2fd251d6f. --- ...ime-To-Buy-and-Sell-Stock-With-Cooldown.py | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py index 7c838a09b..c95b42883 100644 --- a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py +++ b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py @@ -1,27 +1,3 @@ -#state machine & 1D dp -class Solution(object): - def maxProfit(self, prices): - """ - :type prices: List[int] - :rtype: int - """ - sold, held, reset = float('-inf'), float('-inf'), 0 - - for price in prices: - # Alternative: the calculation is done in parallel. - # Therefore no need to keep temporary variables - #sold, held, reset = held + price, max(held, reset-price), max(reset, sold) - - pre_sold = sold - sold = held + price - held = max(held, reset - price) - reset = max(reset, pre_sold) - - return max(sold, reset) - - - - class Solution: def maxProfit(self, prices: List[int]) -> int: # State: Buying or Selling? From 94361d0a5a9cd32da2d6dec5dafe1bcf43870cd9 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 14:28:02 +0100 Subject: [PATCH 38/57] #309 update --- ...ime-To-Buy-and-Sell-Stock-With-Cooldown.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py index c95b42883..7c838a09b 100644 --- a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py +++ b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py @@ -1,3 +1,27 @@ +#state machine & 1D dp +class Solution(object): + def maxProfit(self, prices): + """ + :type prices: List[int] + :rtype: int + """ + sold, held, reset = float('-inf'), float('-inf'), 0 + + for price in prices: + # Alternative: the calculation is done in parallel. + # Therefore no need to keep temporary variables + #sold, held, reset = held + price, max(held, reset-price), max(reset, sold) + + pre_sold = sold + sold = held + price + held = max(held, reset - price) + reset = max(reset, pre_sold) + + return max(sold, reset) + + + + class Solution: def maxProfit(self, prices: List[int]) -> int: # State: Buying or Selling? From 177586b5c8d4ef0d6b8b05cb7c632b634ba9d5d2 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 14:28:46 +0100 Subject: [PATCH 39/57] #518 update --- python/518-coin-change-2.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/python/518-coin-change-2.py b/python/518-coin-change-2.py index 8c3914d1d..65627de50 100644 --- a/python/518-coin-change-2.py +++ b/python/518-coin-change-2.py @@ -13,6 +13,20 @@ def change(self, amount: int, coins: List[int]) -> int: dp[row][col] = dp[row-1][col] + dp[row][col-coins[row]] return dp[-1][-1] +#bottom up 2D dp +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + ROWS = len(coins) + dp = [[0 for i in range(amount+1)] for x in range(ROWS+1)] + for i in range(ROWS+1): + dp[i][0] = 1 + for i in range(1, ROWS+1): + for j in range(1, amount+1): + if coins[i-1] > j: + dp[i][j] = dp[i-1][j] + else: + dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]] + return dp[ROWS][amount] #if we wanted to add a first row of 0s, then row-1 would corespond to coins index class Solution: def change(self, amount: int, coins: List[int]) -> int: From 74052488d5ed362b708b4c22fb18a94f90964848 Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 22:50:42 +0100 Subject: [PATCH 40/57] #91 re-update --- python/91-Decode-ways.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/91-Decode-ways.py b/python/91-Decode-ways.py index d3078ae0b..ca0e7237b 100644 --- a/python/91-Decode-ways.py +++ b/python/91-Decode-ways.py @@ -5,13 +5,12 @@ def numDecodings(self, s: str) -> int: for i in range(len(s)): temp_sum=0 - temp=second if int(s[i]) >0 and int(s[i])<=9: temp_sum+=second if i>0 and int(s[i-1:i+1]) >=10 and int(s[i-1:i+1])<=26: temp_sum+=first + first=second second=temp_sum - first=temp return second From 09829184e9f7bae2cb7952fd7f009c9eec09532a Mon Sep 17 00:00:00 2001 From: Brian Date: Wed, 30 Aug 2023 22:51:04 +0100 Subject: [PATCH 41/57] #213 update --- python/213-House-Robber-II.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/python/213-House-Robber-II.py b/python/213-House-Robber-II.py index ad7fdf484..33bb461e8 100644 --- a/python/213-House-Robber-II.py +++ b/python/213-House-Robber-II.py @@ -3,10 +3,8 @@ def rob(self, nums: List[int]) -> int: return max(nums[0], self.helper(nums[1:]), self.helper(nums[:-1])) def helper(self, nums): - rob1, rob2 = 0, 0 + first,second=0,0 + for i in range(len(nums)): + first,second=second, max(first+nums[i],second) + return second - for n in nums: - newRob = max(rob1 + n, rob2) - rob1 = rob2 - rob2 = newRob - return rob2 From 57f60d0b3c5083ec5329d6bee2042ca79e239082 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 2 Sep 2023 23:07:18 +0100 Subject: [PATCH 42/57] #518 re-update --- python/518-coin-change-2.py | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/python/518-coin-change-2.py b/python/518-coin-change-2.py index 65627de50..55c8d561c 100644 --- a/python/518-coin-change-2.py +++ b/python/518-coin-change-2.py @@ -1,3 +1,21 @@ +#bottom up 2D dp +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + + dp= [[0]* (amount+1) for _ in range(len(coins)+1)] + for row in range(1,len(coins)+1): + dp[row][0]=1 + + for row in range(1,len(coins)+1): + for col in range(1,amount+1): + if col-coins[row-1] >=0: + dp[row][col]=dp[row-1][col]+dp[row][col-coins[row-1]] + else: + dp[row][col]=dp[row-1][col] + + return dp[-1][-1] + + #bottom up 2D dp class Solution: def change(self, amount: int, coins: List[int]) -> int: @@ -13,20 +31,7 @@ def change(self, amount: int, coins: List[int]) -> int: dp[row][col] = dp[row-1][col] + dp[row][col-coins[row]] return dp[-1][-1] -#bottom up 2D dp -class Solution: - def change(self, amount: int, coins: List[int]) -> int: - ROWS = len(coins) - dp = [[0 for i in range(amount+1)] for x in range(ROWS+1)] - for i in range(ROWS+1): - dp[i][0] = 1 - for i in range(1, ROWS+1): - for j in range(1, amount+1): - if coins[i-1] > j: - dp[i][j] = dp[i-1][j] - else: - dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]] - return dp[ROWS][amount] + #if we wanted to add a first row of 0s, then row-1 would corespond to coins index class Solution: def change(self, amount: int, coins: List[int]) -> int: From 8f847577af364e14aa8d905e3db8f0a4c678b946 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 3 Sep 2023 21:31:47 +0100 Subject: [PATCH 43/57] #518 re-update --- python/518-coin-change-2.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/python/518-coin-change-2.py b/python/518-coin-change-2.py index 55c8d561c..f8cbb8ce6 100644 --- a/python/518-coin-change-2.py +++ b/python/518-coin-change-2.py @@ -15,6 +15,18 @@ def change(self, amount: int, coins: List[int]) -> int: return dp[-1][-1] +#bottom up 1D dp- space optimization +class Solution: + def change(self, amount: int, coins: List[int]) -> int: + dp = [0] * (amount + 1) + dp[0] = 1 + + for coin in coins: + for j in range(coin, amount + 1): + dp[j] += dp[j - coin] + + return dp[amount] + #bottom up 2D dp class Solution: From ecf820a4fd7767d4c683579e2877bbdd2794c9ae Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 3 Sep 2023 21:32:05 +0100 Subject: [PATCH 44/57] #416 minor update --- python/416-Partition-Equal-Subset-Sum.py | 27 +++++++++++------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/python/416-Partition-Equal-Subset-Sum.py b/python/416-Partition-Equal-Subset-Sum.py index 0e90e9ee5..7af71b81b 100644 --- a/python/416-Partition-Equal-Subset-Sum.py +++ b/python/416-Partition-Equal-Subset-Sum.py @@ -22,22 +22,19 @@ def canPartition(self, nums: List[int]) -> bool: dp[i][j] = dp[i - 1][j] or dp[i - 1][j - curr] return dp[n][subset_sum] - +from collections.abc import Set class Solution: def canPartition(self, nums: List[int]) -> bool: - if sum(nums) % 2: + total_sum=sum(nums) + if total_sum %2: return False - - dp = set() - dp.add(0) - target = sum(nums) // 2 - - for i in range(len(nums) - 1, -1, -1): - nextDP = set() - for t in dp: - if (t + nums[i]) == target: + half=total_sum//2 + sum_hashset=set() + sum_hashset.add(0) + for num in nums: + hashset_copy=sum_hashset.copy() + for elem in hashset_copy: + if num+elem ==half: return True - nextDP.add(t + nums[i]) - nextDP.add(t) - dp = nextDP - return False + sum_hashset.add(num+elem) + return False \ No newline at end of file From 1826b5068f17c182fba294d34bf37fa39cc677d3 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 3 Sep 2023 21:32:20 +0100 Subject: [PATCH 45/57] #70 update --- python/70-Climbing-Stairs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/70-Climbing-Stairs.py b/python/70-Climbing-Stairs.py index d07bb9d21..3714553d3 100644 --- a/python/70-Climbing-Stairs.py +++ b/python/70-Climbing-Stairs.py @@ -1,7 +1,7 @@ class Solution: def climbStairs(self, n: int) -> int: - first, second= 0,1 - for i in range(n): + first, second= 1,1 + for i in range(n-1): first, second= second, first+second return second From 46cb2c8dfbca24b6eb9bd93464c16d460eec1e17 Mon Sep 17 00:00:00 2001 From: Brian Date: Sun, 3 Sep 2023 23:25:08 +0100 Subject: [PATCH 46/57] #139 minor update --- python/139-Word-Break.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/python/139-Word-Break.py b/python/139-Word-Break.py index 75bba2e79..88658e5e1 100644 --- a/python/139-Word-Break.py +++ b/python/139-Word-Break.py @@ -1,4 +1,16 @@ -#bottom up dynamic programming +#bottom up dynamic programming - with dp padding +class Solution: + def wordBreak(self, s: str, wordDict: List[str]) -> bool: + dp=[False]*(len(s)+1) + dp[0]=True + for i in range(1,len(s)+1): + for word in wordDict: + if i-len(word)>=0 and s[i-len(word):i]==word and dp[i-len(word)]: + dp[i]=True + break + return dp[-1] + +#bottom up dynamic programming - with no dp padding class Solution: def wordBreak(self, s: str, wordDict: List[str]) -> bool: dp = [False] * len(s) From 3755d46a25a1c2b9dbdd58d23278238989a3987f Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:06:30 +0100 Subject: [PATCH 47/57] #1143 update --- python/1143-Longest-Common-Subsequence.py | 58 ++++++++++++++++++----- 1 file changed, 46 insertions(+), 12 deletions(-) diff --git a/python/1143-Longest-Common-Subsequence.py b/python/1143-Longest-Common-Subsequence.py index 29585e981..e950c23fe 100644 --- a/python/1143-Longest-Common-Subsequence.py +++ b/python/1143-Longest-Common-Subsequence.py @@ -1,20 +1,54 @@ +#bottom up 2D dynamic programming class Solution: - def longestCommonSubsequence(self, s1: str, s2: str) -> int: - m = len(s1) - n = len(s2) - memo = [[0 for _ in range(n + 1)] for _ in range(m + 1)] - - for row in range(1, m + 1): - for col in range(1, n + 1): - if s1[row - 1] == s2[col - 1]: - memo[row][col] = 1 + memo[row - 1][col - 1] + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + ROWS=len(text1) + COLS=len(text2) + dp=[[0 for _ in range(COLS+1)] for _ in range(ROWS+1)] + for row in range(1, ROWS+1): + for col in range(1,COLS+1): + if text2[col-1]==text1[row-1]: + dp[row][col]=1+dp[row-1][col-1] else: - memo[row][col] = max(memo[row][col - 1], memo[row - 1][col]) - - return memo[m][n] + dp[row][col]=max(dp[row-1][col],dp[row][col-1]) + return dp[-1][-1] +#bottom up 1D dynamic programming- memory optimization with two rows +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + if len(text1) < len(text2): + text1,text2=text2,text1 + ROWS=len(text1) + COLS=len(text2) + above=[0 for _ in range(COLS+1)] + for row in range(1,ROWS+1): + current=[0]* (COLS+1) + for col in range(1,COLS+1): + if text2[col-1]==text1[row-1]: + current[col]=1+above[col-1] + else: + current[col]=max(above[col],current[col-1]) + + above=current + return current[-1] +#bottom up 1D dynamic programming- memory optimization with two rows- minor time optimization +class Solution: + def longestCommonSubsequence(self, text1: str, text2: str) -> int: + if len(text1) < len(text2): + text1,text2=text2,text1 + ROWS=len(text1) + COLS=len(text2) + above=[0 for _ in range(COLS+1)] + current=[0]* (COLS+1) + for row in range(1,ROWS+1): + for col in range(1,COLS+1): + if text2[col-1]==text1[row-1]: + current[col]=1+above[col-1] + else: + current[col]=max(above[col],current[col-1]) + current,above=above,current + return above[-1] class Solution: From 136b69559533be65af2f9542c64e40d214751900 Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:06:51 +0100 Subject: [PATCH 48/57] #309 update --- ...t-Time-To-Buy-and-Sell-Stock-With-Cooldown.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py index 7c838a09b..660fd82b1 100644 --- a/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py +++ b/python/309-Best-Time-To-Buy-and-Sell-Stock-With-Cooldown.py @@ -1,3 +1,19 @@ +#state machine & dp with 3 arrays +class Solution: + def maxProfit(self, prices: List[int]) -> int: + length=len(prices) + sold,reset,hold=[0]*(length+1),[0]*(length+1),[0]*(length+1) + reset[0]=0 + hold[0]=sold[0]=float('-inf') + for i in range(1,length+1): + sold[i]=hold[i-1]+prices[i-1] + reset[i]=max(sold[i-1],reset[i-1]) + hold[i]=max(hold[i-1],reset[i-1]-prices[i-1]) + print(sold,reset,hold) + return max(sold[-1],reset[-1]) + + + #state machine & 1D dp class Solution(object): def maxProfit(self, prices): From b5605c025d9d54526636f4da59a25fe226ed909e Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:07:02 +0100 Subject: [PATCH 49/57] #494 update --- python/494-Target-Sum.py | 28 ++++++++++++---------------- 1 file changed, 12 insertions(+), 16 deletions(-) diff --git a/python/494-Target-Sum.py b/python/494-Target-Sum.py index 1ba8ab6aa..652355fd2 100644 --- a/python/494-Target-Sum.py +++ b/python/494-Target-Sum.py @@ -20,23 +20,19 @@ def findTargetSumWays(self, nums: List[int], S: int) -> int: ## SPACE COMPLEXITY : O(N^2) ## totalSum = sum(nums) + ROWS= len(nums) if(S not in range(-1 * totalSum, totalSum + 1) ): return 0 - dp = [ [ 0 for j in range( totalSum*2 + 1 ) ] for i in range(len(nums))] - - ## BASE CASE ## FIRST ROW ## - dp[0][totalSum + nums[0]] += 1 - dp[0][totalSum - nums[0]] += 1 - - for i in range(1, len(nums)): - for j in range( totalSum*2 + 1 ): - - if( j - nums[i] >= 0 and dp[i-1][j-nums[i]] > 0 ): # left side - dp[i][j] += dp[i-1][j-nums[i]] - - if( j + nums[i] <= totalSum*2 and dp[i-1][j+nums[i]] > 0 ): # right side - dp[i][j] += dp[i-1][j+nums[i]] - - print(dp) + dp= [[0]*(totalSum*2+1) for _ in range(ROWS+1)] + dp[0][totalSum]=1 + + + for row in range(1,ROWS+1): + for col in range(totalSum*2 + 1): + if col - nums[row-1] >= 0: # left side + dp[row][col] += dp[row-1][col-nums[row-1]] + if col + nums[row-1] <= totalSum*2: # right side + dp[row][col] += dp[row-1][col+nums[row-1]] + return dp[-1][totalSum + S] From 1b9da12aaf7e985a9d7d78014604ab961aa51f0b Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:07:15 +0100 Subject: [PATCH 50/57] #62 update --- python/62-Unique-Paths.py | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/python/62-Unique-Paths.py b/python/62-Unique-Paths.py index fb2173b62..c3fb1272e 100644 --- a/python/62-Unique-Paths.py +++ b/python/62-Unique-Paths.py @@ -1,4 +1,16 @@ -#bottom up dynamic programming +#bottom up 2D dynamic programming +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + dp=[[0] *(n+1) for _ in range(m+1)] + dp[1][0]=1 + for row in range(1,m+1): + for col in range(1,n+1): + dp[row][col]=dp[row-1][col]+dp[row][col-1] + print(dp) + return dp[-1][-1] + + +#bottom up 2D dynamic programming class Solution: def uniquePaths(self, m: int, n: int) -> int: d = [[1] * n for _ in range(m)] @@ -9,9 +21,33 @@ def uniquePaths(self, m: int, n: int) -> int: return d[m - 1][n - 1] +#bottom up 1D dynamic programming- memory optimization with one row one variable +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + dp=[0]*(n) + dp[0]=1 + for _ in range(m): + prev=0 + for col in range(n): + dp[col]+=prev + prev=dp[col] + return dp[-1] + +#bottom up 1D dynamic programming- memory optimization with 2 rows +class Solution: + def uniquePaths(self, m: int, n: int) -> int: + aboveRow = [1] * n + for _ in range(m - 1): + currentRow = [1] * n + for i in range(1, n): + currentRow[i] = currentRow[i-1] + aboveRow[i] + aboveRow = currentRow + return aboveRow[-1] + + class Solution: def uniquePaths(self, m: int, n: int) -> int: row = [1] * n From 29880ec80016abb4ae764591b87cd99e59c0bfac Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:07:32 +0100 Subject: [PATCH 51/57] #72 update --- python/72-Edit-Distance.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/python/72-Edit-Distance.py b/python/72-Edit-Distance.py index d26fa4681..6693a6b1b 100644 --- a/python/72-Edit-Distance.py +++ b/python/72-Edit-Distance.py @@ -1,3 +1,28 @@ +#also next solution is good. this one initializes row 0 and col 0 in the same loop. next one has separate loops +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + COLS=len(word1) + ROWS=len(word2) + + dp=[[0]*(COLS+1) for _ in range(ROWS+1)] + + for row in range(ROWS+1): + for col in range(COLS+1): + if row==0 and col==0: + continue + if row==0: + dp[row][col]=1+ dp[row][col-1] + elif col==0: + dp[row][col]=1+ dp[row-1][col] + + else: + if word1[col-1]== word2[row-1]: + dp[row][col]=dp[row-1][col-1] + else: + dp[row][col]=1+ min(dp[row-1][col],dp[row][col-1],dp[row-1][col-1]) + return dp[-1][-1] + + #bottom up 2D dp class Solution: def minDistance(self, word1: str, word2: str) -> int: From 707ab42c41b37796d5953f76dd62f6b43774f09a Mon Sep 17 00:00:00 2001 From: Brian Date: Sat, 9 Sep 2023 21:07:44 +0100 Subject: [PATCH 52/57] #97 update --- python/97-Interleaving-Strings.py | 63 ++++++++++++++++++++++--------- 1 file changed, 46 insertions(+), 17 deletions(-) diff --git a/python/97-Interleaving-Strings.py b/python/97-Interleaving-Strings.py index 62a98c8fe..ebf139293 100644 --- a/python/97-Interleaving-Strings.py +++ b/python/97-Interleaving-Strings.py @@ -1,23 +1,52 @@ +#2D Dynamic programing- start from row 0 coloum 0 class Solution: def isInterleave(self, s1: str, s2: str, s3: str) -> bool: - m, n, l = len(s1), len(s2), len(s3) - if m + n != l: - return False - - dp = [[False] * (n + 1) for _ in range(m + 1)] - dp[0][0] = True - - for i in range(1, m + 1): - dp[i][0] = dp[i-1][0] and s1[i-1] == s3[i-1] - - for j in range(1, n + 1): - dp[0][j] = dp[0][j-1] and s2[j-1] == s3[j-1] - - for i in range(1, m + 1): - for j in range(1, n + 1): - dp[i][j] = (dp[i-1][j] and s1[i-1] == s3[i+j-1]) or (dp[i][j-1] and s2[j-1] == s3[i+j-1]) + ROWS=len(s2) + COLS=len(s1) + if len(s3) != ROWS+COLS:return False + dp=[[False for _ in range(COLS+1)] for _ in range(ROWS+1)] + dp[0][0]=True + for row in range(ROWS+1): + for col in range(COLS+1): + if col>0 and s3[row+col-1]==s1[col-1]: + if dp[row][col-1]: + dp[row][col]= True + + if row>0 and s3[row+col-1]==s2[row-1]: + if dp[row-1][col]: + dp[row][col]= True + + return dp[-1][-1] + +class Solution: + def isInterleave(self, s1: str, s2: str, s3: str) -> bool: + ROWS=len(s2) + COLS=len(s1) + if len(s3) != ROWS+COLS:return False + dp=[[False for _ in range(COLS+1)] for _ in range(ROWS+1)] + dp[0][0]=True + + for row in range(1,ROWS+1): + if s3[row-1]==s2[row-1]: + if dp[row-1][0]: + dp[row][0]= True + for col in range(1,COLS+1): + if s3[col-1]==s1[col-1]: + if dp[0][col-1]: + dp[0][col]= True - return dp[m][n] + + for row in range(1,ROWS+1): + for col in range(1,COLS+1): + if s3[row+col-1]==s1[col-1]: + if dp[row][col-1]: + dp[row][col]= True + + if s3[row+col-1]==s2[row-1]: + if dp[row-1][col]: + dp[row][col]= True + + return dp[-1][-1] From ec25ffb67f87dd950d4d72d258ed6a7d868b0ecb Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 11 Sep 2023 21:09:36 +0100 Subject: [PATCH 53/57] #115 minor update --- python/115-Distinct-Subsequences.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/python/115-Distinct-Subsequences.py b/python/115-Distinct-Subsequences.py index b6df28ba0..c9d517d9f 100644 --- a/python/115-Distinct-Subsequences.py +++ b/python/115-Distinct-Subsequences.py @@ -7,15 +7,12 @@ def numDistinct(self, s: str, t: str) -> int: for i in range(m+1): dp[i][0] = 1 - """redundant, as we have initialised dp table with full of zeros""" -# for i in range(1, n+1): -# dp[0][i] = 0 for i in range(1, m+1): for j in range(1, n+1): - dp[i][j] += dp[i-1][j] #if current character is skipped + dp[i][j] += dp[i-1][j] if s[i-1] == t[j-1]: - dp[i][j] += dp[i-1][j-1] #if current character is used + dp[i][j] += dp[i-1][j-1] return dp[-1][-1] From cb77f32430a4b3459dbe6da73dc8d58db0e5b455 Mon Sep 17 00:00:00 2001 From: Brian Date: Mon, 11 Sep 2023 21:09:53 +0100 Subject: [PATCH 54/57] #10 update --- python/10-Regular-Expression-Matching.py | 36 ++++++++++++++---------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/python/10-Regular-Expression-Matching.py b/python/10-Regular-Expression-Matching.py index 06dc1c784..b2bd9c665 100644 --- a/python/10-Regular-Expression-Matching.py +++ b/python/10-Regular-Expression-Matching.py @@ -1,21 +1,27 @@ #bottom up 2D dp class Solution: - def isMatch(self, s, p): - dp = [[False] * (len(s) + 1) for _ in range(len(p) + 1)] + def isMatch(self, s: str, p: str) -> bool: + lenS, lenP = len(s), len(p) + dp = [[False]*(lenP+1) for i in range(lenS+1)] dp[0][0] = True - for i in range(2, len(p)): - dp[i][0] = dp[i - 2][0] and p[i-1] == '*' - for i in range(1, len(p)+1): - for j in range(1,len(s)+1): - if p[i-1] == '*': - dp[i][j] = dp[i - 2][j] or dp[i-1][j] - if p[i - 2] == s[j-1] or p[i - 2] == '.': - dp[i][j] |= dp[i][j-1] - else: - dp[i][j] = dp[i-1][j-1] and (p[i-1] == s[j-1] or p[i-1] == '.') - return dp[-1][-1] - - + + for j in range(1, lenP+1): + if p[j-1] == '*': + dp[0][j] = dp[0][j-2] + + for i in range(1, lenS+1): + for j in range(1, lenP+1): + #if chars match look top left + if p[j-1] in {s[i-1], '.'}: + dp[i][j] = dp[i-1][j-1] + #if we have a * char: + #1. not to use the previous char + #2. look one col up, if True, it was possible to make the previous chars in s with some number of * + #so check if it is possible to make the last char with * as well? (therefore the char before * should match the last s char) + elif p[j-1] == "*": + dp[i][j] = dp[i][j-2] or (dp[i-1][j] and p[j-2] in {s[i-1], '.'}) + + return dp[-1][-1] # BOTTOM-UP Dynamic Programming From ef2e26f0c376b44dd79572492a92fa93320ce982 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 14 Sep 2023 22:02:08 +0100 Subject: [PATCH 55/57] #198 update --- python/198-House-Robber.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/198-House-Robber.py b/python/198-House-Robber.py index 904c94f4e..611deefad 100644 --- a/python/198-House-Robber.py +++ b/python/198-House-Robber.py @@ -15,6 +15,24 @@ def helper(n): return hashmap[n] return helper(len(nums)-1) +#recursive with memo +class Solution: + def rob(self, nums: List[int]) -> int: + hashmap={} + def helper(n): + if n not in hashmap: + if n==0: + hashmap[0]=nums[0] + elif n==1: + hashmap[1]=max(nums[0],nums[1]) + else: + hashmap[n]=max(helper(n-1), helper(n-2)+nums[n]) + + return hashmap[n] + + return helper(len(nums)-1) + + class Solution: def rob(self, nums: List[int]) -> int: # edge cases: From f78adac4c99d8c56896089b4eb19e70691ddd969 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 14 Sep 2023 22:02:28 +0100 Subject: [PATCH 56/57] #213 update --- python/213-House-Robber-II.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/python/213-House-Robber-II.py b/python/213-House-Robber-II.py index 33bb461e8..8e82dd3eb 100644 --- a/python/213-House-Robber-II.py +++ b/python/213-House-Robber-II.py @@ -8,3 +8,27 @@ def helper(self, nums): first,second=second, max(first+nums[i],second) return second +#recursive top down with memo +class Solution: + def rob(self, nums: List[int]) -> int: + hashmap={} + + def helper(n, nums): + if len(nums)==0: + return 0 + if n not in hashmap: + if n==0: + hashmap[0]=nums[0] + elif n==1: + hashmap[1]=max(nums[0],nums[1]) + else: + hashmap[n]=max(helper(n-1,nums), helper(n-2,nums)+nums[n]) + + return hashmap[n] + + + a=helper(len(nums)-2,nums[0:-1]) + hashmap={} + b=helper(len(nums)-2,nums[1:]) + + return max(nums[0],a,b) \ No newline at end of file From 91984dd83c0887d61edcbd4b89867bf2acc38b24 Mon Sep 17 00:00:00 2001 From: Brian Date: Thu, 14 Sep 2023 22:02:43 +0100 Subject: [PATCH 57/57] #70 update --- python/70-Climbing-Stairs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/70-Climbing-Stairs.py b/python/70-Climbing-Stairs.py index 3714553d3..b12a824fb 100644 --- a/python/70-Climbing-Stairs.py +++ b/python/70-Climbing-Stairs.py @@ -7,7 +7,7 @@ def climbStairs(self, n: int) -> int: class Solution: def climbStairs(self, n: int) -> int: - hashmap={-1:0,0:1} + hashmap={0:1,1:1} def helper(n): if n not in hashmap: hashmap[n]=helper(n-1)+helper(n-2)