From 67142bcef92f36980b450572f4adb4c66dce9ef8 Mon Sep 17 00:00:00 2001 From: arichen Date: Thu, 22 Oct 2020 23:31:53 -0700 Subject: [PATCH 01/20] week01 homework --- week01/189.py | 20 ++++++++++++++++++++ week01/21.py | 20 ++++++++++++++++++++ week01/26.py | 8 ++++++++ 3 files changed, 48 insertions(+) create mode 100644 week01/189.py create mode 100644 week01/21.py create mode 100644 week01/26.py diff --git a/week01/189.py b/week01/189.py new file mode 100644 index 00000000..0c8a7a9f --- /dev/null +++ b/week01/189.py @@ -0,0 +1,20 @@ +class Solution: + def rotate(self, nums: List[int], k: int) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + count, n = 0, len(nums) + k %= n + + start = 0 + while count < n: + current = start + while True: + next_idx = (current + k) % n + nums[start], nums[next_idx] = nums[next_idx], nums[start] + current = next_idx + count += 1 + + if current == start: + break + start += 1 \ No newline at end of file diff --git a/week01/21.py b/week01/21.py new file mode 100644 index 00000000..eb126409 --- /dev/null +++ b/week01/21.py @@ -0,0 +1,20 @@ +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def mergeTwoLists(self, l1: ListNode, l2: ListNode) -> ListNode: + prev = prehead = ListNode() + + while l1 and l2: + if l1.val <= l2.val: + prev.next = l1 + l1 = l1.next + else: + prev.next = l2 + l2 = l2.next + prev = prev.next + + prev.next = l1 if l1 else l2 + return prehead.next \ No newline at end of file diff --git a/week01/26.py b/week01/26.py new file mode 100644 index 00000000..dec81e55 --- /dev/null +++ b/week01/26.py @@ -0,0 +1,8 @@ +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + count = 1 + for i in range(1, len(nums)): + if nums[i] != nums[i - 1]: + nums[count] = nums[i] + count += 1 + return count \ No newline at end of file From 602686c7951f7075e768cdf2b8dfa8885ba8e75e Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 24 Oct 2020 22:27:36 -0700 Subject: [PATCH 02/20] homework01 --- week01/1.py | 8 ++++++++ week01/283.py | 10 ++++++++++ week01/4.py | 20 ++++++++++++++++++++ week01/66.py | 7 +++++++ 4 files changed, 45 insertions(+) create mode 100644 week01/1.py create mode 100644 week01/283.py create mode 100644 week01/4.py create mode 100644 week01/66.py diff --git a/week01/1.py b/week01/1.py new file mode 100644 index 00000000..ff0ca2cc --- /dev/null +++ b/week01/1.py @@ -0,0 +1,8 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + d = {} + for i, v in enumerate(nums): + if target - v in d: + return [i, d[target - v]] + else: + d[v] = i diff --git a/week01/283.py b/week01/283.py new file mode 100644 index 00000000..e9bde678 --- /dev/null +++ b/week01/283.py @@ -0,0 +1,10 @@ +class Solution: + def moveZeroes(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + pos = 0 + for i in range(len(nums)): + if nums[i] != 0: + nums[i], nums[pos] = nums[pos], nums[i] + pos += 1 diff --git a/week01/4.py b/week01/4.py new file mode 100644 index 00000000..60f95670 --- /dev/null +++ b/week01/4.py @@ -0,0 +1,20 @@ +class Solution: + def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None: + """ + Do not return anything, modify nums1 in-place instead. + """ + if not nums1 or not nums2: + return + + q = len(nums1) - 1 + p1, p2 = m - 1, n - 1 + + while p2 >= 0: + if p1 < 0 or nums2[p2] >= nums1[p1]: + nums1[q] = nums2[p2] + p2 -= 1 + q -= 1 + else: + nums1[q], nums1[p1] = nums1[p1], nums1[q] + q -= 1 + p1 -= 1 \ No newline at end of file diff --git a/week01/66.py b/week01/66.py new file mode 100644 index 00000000..0da14bbe --- /dev/null +++ b/week01/66.py @@ -0,0 +1,7 @@ +class Solution: + def plusOne(self, digits: List[int]) -> List[int]: + for i in range(len(digits) - 1, -1, -1): + digits[i] = (digits[i] + 1) % 10 + if digits[i] != 0: + return digits + return [1] + digits \ No newline at end of file From 0d76acf1acd539102991b753e50c4e86fb43cbba Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 24 Oct 2020 22:33:28 -0700 Subject: [PATCH 03/20] homework01 note --- week01/NOTE.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/week01/NOTE.md b/week01/NOTE.md index 50de3041..79a5f342 100644 --- a/week01/NOTE.md +++ b/week01/NOTE.md @@ -1 +1,2 @@ -学习笔记 \ No newline at end of file +Tips: +- Focus on learning the best solution, instead of use up all the energy on coming up with your own solution and tire out. \ No newline at end of file From 3e5ed015cf659f01f19d73e3fe0337620fd90e3d Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 24 Oct 2020 23:17:54 -0700 Subject: [PATCH 04/20] homework 01 --- week01/641.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ week01/NOTE.md | 4 +-- 2 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 week01/641.py diff --git a/week01/641.py b/week01/641.py new file mode 100644 index 00000000..24ad78f5 --- /dev/null +++ b/week01/641.py @@ -0,0 +1,86 @@ +class MyCircularDeque: + + def __init__(self, k: int): + """ + Initialize your data structure here. Set the size of the deque to be k. + """ + self.size = k + self.data = [None] * k + self.start = 0 + self.length = 0 + + def insertFront(self, value: int) -> bool: + """ + Adds an item at the front of Deque. Return true if the operation is successful. + """ + if self.length == self.size: + return False + + if self.length == 0: + self.data[self.start] = value + else: + self.start = (self.start + self.size - 1) % self.size + self.data[self.start] = value + self.length += 1 + return True + + def insertLast(self, value: int) -> bool: + """ + Adds an item at the rear of Deque. Return true if the operation is successful. + """ + if self.length == self.size: + return False + + end = (self.start + self.length) % self.size + self.data[end] = value + self.length += 1 + return True + + def deleteFront(self) -> bool: + """ + Deletes an item from the front of Deque. Return true if the operation is successful. + """ + if self.length == 0: + return False + + self.start = (self.start + 1) % self.size + self.length -= 1 + return True + + def deleteLast(self) -> bool: + """ + Deletes an item from the rear of Deque. Return true if the operation is successful. + """ + if self.length == 0: + return False + + self.length -= 1 + return True + + def getFront(self) -> int: + """ + Get the front item from the deque. + """ + if self.length == 0: + return -1 + return self.data[self.start] + + def getRear(self) -> int: + """ + Get the last item from the deque. + """ + if self.length == 0: + return -1 + return self.data[(self.start + self.length - 1) % self.size] + + def isEmpty(self) -> bool: + """ + Checks whether the circular deque is empty or not. + """ + return self.length == 0 + + def isFull(self) -> bool: + """ + Checks whether the circular deque is full or not. + """ + return self.length == self.size diff --git a/week01/NOTE.md b/week01/NOTE.md index 79a5f342..4126382a 100644 --- a/week01/NOTE.md +++ b/week01/NOTE.md @@ -1,2 +1,2 @@ -Tips: -- Focus on learning the best solution, instead of use up all the energy on coming up with your own solution and tire out. \ No newline at end of file +## Tips: +- Read and learn the best solution, instead of focusing on reinventing your own wheel. From f9efa06e14902ad049388d96806bb93db25ba160 Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 31 Oct 2020 23:14:15 -0700 Subject: [PATCH 05/20] week02 homework --- week02/144_binary_tree_preorder_traversal.py | 18 +++++++++++++++ week02/1_two_sum.py | 8 +++++++ week02/242_valid_anagram.py | 4 ++++ .../429_n_ary_tree_level_order_traversal.py | 22 +++++++++++++++++++ week02/49_group_anagrams.py | 10 +++++++++ week02/589_n_ary_tree_preorder_traversal.py | 19 ++++++++++++++++ week02/94_binary_tree_inorder_traversal.py | 16 ++++++++++++++ 7 files changed, 97 insertions(+) create mode 100644 week02/144_binary_tree_preorder_traversal.py create mode 100644 week02/1_two_sum.py create mode 100644 week02/242_valid_anagram.py create mode 100644 week02/429_n_ary_tree_level_order_traversal.py create mode 100644 week02/49_group_anagrams.py create mode 100644 week02/589_n_ary_tree_preorder_traversal.py create mode 100644 week02/94_binary_tree_inorder_traversal.py diff --git a/week02/144_binary_tree_preorder_traversal.py b/week02/144_binary_tree_preorder_traversal.py new file mode 100644 index 00000000..ed2216e6 --- /dev/null +++ b/week02/144_binary_tree_preorder_traversal.py @@ -0,0 +1,18 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def preorderTraversal(self, root: TreeNode, path: list = None) -> List[int]: + if not root: + return [] + + stack, res = [root], [] + while stack: + node = stack.pop() + if node: + res.append(node.val) + stack += [node.right, node.left] + return res \ No newline at end of file diff --git a/week02/1_two_sum.py b/week02/1_two_sum.py new file mode 100644 index 00000000..ff0ca2cc --- /dev/null +++ b/week02/1_two_sum.py @@ -0,0 +1,8 @@ +class Solution: + def twoSum(self, nums: List[int], target: int) -> List[int]: + d = {} + for i, v in enumerate(nums): + if target - v in d: + return [i, d[target - v]] + else: + d[v] = i diff --git a/week02/242_valid_anagram.py b/week02/242_valid_anagram.py new file mode 100644 index 00000000..50a683df --- /dev/null +++ b/week02/242_valid_anagram.py @@ -0,0 +1,4 @@ +from collections import Counter +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return Counter(s) == Counter(t) \ No newline at end of file diff --git a/week02/429_n_ary_tree_level_order_traversal.py b/week02/429_n_ary_tree_level_order_traversal.py new file mode 100644 index 00000000..4ff3fd48 --- /dev/null +++ b/week02/429_n_ary_tree_level_order_traversal.py @@ -0,0 +1,22 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + +class Solution: + def levelOrder(self, root: 'Node') -> List[List[int]]: + if not root: + return [] + + queue, res = [root], [] + while queue: + q, r = [], [] + for node in queue: + r.append(node.val) + q += node.children + queue = q + res.append(r) + return res \ No newline at end of file diff --git a/week02/49_group_anagrams.py b/week02/49_group_anagrams.py new file mode 100644 index 00000000..9d843823 --- /dev/null +++ b/week02/49_group_anagrams.py @@ -0,0 +1,10 @@ +from collections import defaultdict +class Solution: + def groupAnagrams(self, strs: List[str]) -> List[List[str]]: + res = defaultdict(list) + for s in strs: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + res[tuple(count)].append(s) + return list(res.values()) \ No newline at end of file diff --git a/week02/589_n_ary_tree_preorder_traversal.py b/week02/589_n_ary_tree_preorder_traversal.py new file mode 100644 index 00000000..d9fe6c1a --- /dev/null +++ b/week02/589_n_ary_tree_preorder_traversal.py @@ -0,0 +1,19 @@ +""" +# Definition for a Node. +class Node: + def __init__(self, val=None, children=None): + self.val = val + self.children = children +""" + +class Solution: + def preorder(self, root: 'Node') -> List[int]: + if not root: + return [] + + stack, res = [root], [] + while stack: + node = stack.pop() + res.append(node.val) + stack += node.children[::-1] + return res \ No newline at end of file diff --git a/week02/94_binary_tree_inorder_traversal.py b/week02/94_binary_tree_inorder_traversal.py new file mode 100644 index 00000000..42224960 --- /dev/null +++ b/week02/94_binary_tree_inorder_traversal.py @@ -0,0 +1,16 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def inorderTraversal(self, root: TreeNode, path: list = None) -> List[int]: + path = path or [] + if not root: + return path + + path += self.inorderTraversal(root.left) + path.append(root.val) + path += self.inorderTraversal(root.right) + return path \ No newline at end of file From 91879eac4e8b526de73ec3a61d1f54b659abfc91 Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 31 Oct 2020 23:27:41 -0700 Subject: [PATCH 06/20] week02 homework note --- week02/NOTE.md | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/week02/NOTE.md b/week02/NOTE.md index 50de3041..1ff85916 100644 --- a/week02/NOTE.md +++ b/week02/NOTE.md @@ -1 +1,31 @@ -学习笔记 \ No newline at end of file +## Tree Traversal +- Iteration + - Preorder: append children to the end of stack in reverse order (right -> left) + ``` + class Solution: + def preorder(self, root: 'Node') -> List[int]: + if not root: + return [] + + stack, res = [root], [] + while stack: + node = stack.pop() + res.append(node.val) + stack += node.children[::-1] + return res + ``` + - Postorder: append children to the end in normal order (left -> right), reverse the final output + ``` + class Solution: + def postorder(self, root: 'Node') -> List[int]: + if not root: + return [] + + stack, res = [root], [] + while stack: + node = stack.pop() + res.append(node.val) + for c in node.children: + stack.append(c) + return res[::-1] + ``` \ No newline at end of file From 7e4ebdba0ad32559ad1ff52271e951f8541f9512 Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 31 Oct 2020 23:29:39 -0700 Subject: [PATCH 07/20] week02 homework note --- week02/NOTE.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/week02/NOTE.md b/week02/NOTE.md index 1ff85916..c2579ebe 100644 --- a/week02/NOTE.md +++ b/week02/NOTE.md @@ -1,7 +1,8 @@ ## Tree Traversal -- Iteration +- ### Iterations - Preorder: append children to the end of stack in reverse order (right -> left) - ``` + + ```python class Solution: def preorder(self, root: 'Node') -> List[int]: if not root: @@ -14,8 +15,10 @@ stack += node.children[::-1] return res ``` + - Postorder: append children to the end in normal order (left -> right), reverse the final output - ``` + + ```python class Solution: def postorder(self, root: 'Node') -> List[int]: if not root: @@ -28,4 +31,4 @@ for c in node.children: stack.append(c) return res[::-1] - ``` \ No newline at end of file + ``` From 5eb27a0ff51a5d0b082c6390a3e0be5dbba23a52 Mon Sep 17 00:00:00 2001 From: arichen Date: Tue, 3 Nov 2020 15:15:39 -0800 Subject: [PATCH 08/20] more homework02 --- week02/264_ugly_number.py | 20 ++++++++++++++++++++ week02/347_top_k_frequent_elements.py | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 week02/264_ugly_number.py create mode 100644 week02/347_top_k_frequent_elements.py diff --git a/week02/264_ugly_number.py b/week02/264_ugly_number.py new file mode 100644 index 00000000..4020bd61 --- /dev/null +++ b/week02/264_ugly_number.py @@ -0,0 +1,20 @@ +class Solution: + def genUgly(self, n: int = 1690) -> int: + nums = [1] + p2 = p3 = p5 = 0 + + for i in range(1, n): + v = min(nums[p2] * 2, nums[p3] * 3, nums[p5] * 5) + nums.append(v) + + if v == nums[p2] * 2: + p2 += 1 + if v == nums[p3] * 3: + p3 += 1 + if v == nums[p5] * 5: + p5 += 1 + return nums + + def nthUglyNumber(self, n: int) -> int: + nums = self.genUgly(n) + return nums[-1] \ No newline at end of file diff --git a/week02/347_top_k_frequent_elements.py b/week02/347_top_k_frequent_elements.py new file mode 100644 index 00000000..3bdaf990 --- /dev/null +++ b/week02/347_top_k_frequent_elements.py @@ -0,0 +1,9 @@ +from collections import Counter +from heapq import nlargest +class Solution: + def topKFrequent(self, nums: List[int], k: int) -> List[int]: + if k == len(nums): + return nums + + c = Counter(nums) + return nlargest(k, c, c.get) \ No newline at end of file From b0d37a044b80cc478ca7d2a030117ab917dd3e81 Mon Sep 17 00:00:00 2001 From: arichen Date: Sun, 8 Nov 2020 08:03:16 -0800 Subject: [PATCH 09/20] homework 03 --- week03/105_binary_tree_preorder_inorder.py | 17 +++++++++++++++ week03/236_lowest_common_ancestor.py | 25 ++++++++++++++++++++++ week03/46_permutations.py | 14 ++++++++++++ week03/47_permutations_II.py | 14 ++++++++++++ week03/77_combinations.py | 15 +++++++++++++ 5 files changed, 85 insertions(+) create mode 100644 week03/105_binary_tree_preorder_inorder.py create mode 100644 week03/236_lowest_common_ancestor.py create mode 100644 week03/46_permutations.py create mode 100644 week03/47_permutations_II.py create mode 100644 week03/77_combinations.py diff --git a/week03/105_binary_tree_preorder_inorder.py b/week03/105_binary_tree_preorder_inorder.py new file mode 100644 index 00000000..64fef323 --- /dev/null +++ b/week03/105_binary_tree_preorder_inorder.py @@ -0,0 +1,17 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: + if not all([preorder, inorder]): + return + + root = TreeNode(preorder[0]) + length, index = len(preorder), inorder.index(preorder[0]) + + root.left = self.buildTree(preorder[1: index + 1], inorder[: index]) + root.right = self.buildTree(preorder[index + 1:], inorder[index + 1:]) + return root \ No newline at end of file diff --git a/week03/236_lowest_common_ancestor.py b/week03/236_lowest_common_ancestor.py new file mode 100644 index 00000000..199966a2 --- /dev/null +++ b/week03/236_lowest_common_ancestor.py @@ -0,0 +1,25 @@ +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + lca = None + + def hasNodes(self, root, targets): + if not root: + return False + + occur = (root in targets) + self.hasNodes(root.left, targets) + self.hasNodes(root.right, targets) + if occur >= 2: + # target nodes are at either (root, left tree), (root, right tree), or (left tree, right tree) + self.lca = root + + return occur > 0 + + + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + self.hasNodes(root, [p, q]) + return self.lca \ No newline at end of file diff --git a/week03/46_permutations.py b/week03/46_permutations.py new file mode 100644 index 00000000..87ac6d2b --- /dev/null +++ b/week03/46_permutations.py @@ -0,0 +1,14 @@ +class Solution: + res = [] + + def permute(self, nums: List[int]) -> List[List[int]]: + def _recur(l, path): + if not l: + self.res.append(path) + return + for i in range(len(l)): + _recur(l[:i] + l[i + 1:], path + [l[i]]) + + self.res = [] + _recur(nums, []) + return self.res \ No newline at end of file diff --git a/week03/47_permutations_II.py b/week03/47_permutations_II.py new file mode 100644 index 00000000..a77d1c52 --- /dev/null +++ b/week03/47_permutations_II.py @@ -0,0 +1,14 @@ +class Solution: + def backtrack(self, nums: List[int], path: List[int], res: List[List[int]]): + if not nums: + res.append(path) + for i in range(len(nums)): + if i > 0 and nums[i] == nums[i - 1]: + continue + self.backtrack(nums[:i] + nums[i + 1:], path + [nums[i]], res) + + def permuteUnique(self, nums: List[int]) -> List[List[int]]: + res = [] + nums = sorted(nums) + self.backtrack(nums, [], res) + return res \ No newline at end of file diff --git a/week03/77_combinations.py b/week03/77_combinations.py new file mode 100644 index 00000000..a93ab7a0 --- /dev/null +++ b/week03/77_combinations.py @@ -0,0 +1,15 @@ +class Solution: + res = [] + + def combine(self, n: int, k: int) -> List[List[int]]: + def _backtrack(level, start, path): + if level == k: + self.res.append(path) + return + + for i in range(start, n + 1): + _backtrack(level + 1, i + 1, path + [i]) + + self.res = [] + _backtrack(0, 1, []) + return self.res \ No newline at end of file From 8b28b4cdfe1f504058e322e726b47861ab081bf4 Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 14 Nov 2020 22:32:35 -0800 Subject: [PATCH 10/20] homework04 --- week04/122_best_buy_sell_stock_II.py | 10 ++++++ week04/127_word_ladder.py | 34 ++++++++++++++++++++ week04/200_number_of_islands.py | 29 +++++++++++++++++ week04/455_assign_cookies.py | 13 ++++++++ week04/529_minesweeper.py | 43 ++++++++++++++++++++++++++ week04/55_jump_game.py | 9 ++++++ week04/860_lemonade_change.py | 15 +++++++++ week04/874_walking_robot_simulation.py | 21 +++++++++++++ 8 files changed, 174 insertions(+) create mode 100644 week04/122_best_buy_sell_stock_II.py create mode 100644 week04/127_word_ladder.py create mode 100644 week04/200_number_of_islands.py create mode 100644 week04/455_assign_cookies.py create mode 100644 week04/529_minesweeper.py create mode 100644 week04/55_jump_game.py create mode 100644 week04/860_lemonade_change.py create mode 100644 week04/874_walking_robot_simulation.py diff --git a/week04/122_best_buy_sell_stock_II.py b/week04/122_best_buy_sell_stock_II.py new file mode 100644 index 00000000..5c5bc2dc --- /dev/null +++ b/week04/122_best_buy_sell_stock_II.py @@ -0,0 +1,10 @@ +class Solution: + def maxProfit(self, prices: List[int]) -> int: + if not prices: + return 0 + + total = 0 + for i in range(1, len(prices)): + if prices[i] > prices[i - 1]: + total += prices[i] - prices[i - 1] + return total \ No newline at end of file diff --git a/week04/127_word_ladder.py b/week04/127_word_ladder.py new file mode 100644 index 00000000..ff3ec293 --- /dev/null +++ b/week04/127_word_ladder.py @@ -0,0 +1,34 @@ +from collections import defaultdict +class Solution: + def __init__(self): + self.wordMap = None + + def buildMap(self, wordList: List[str]): + self.wordMap = defaultdict(list) + for s in wordList: + for k in self.mapKeys(s): + self.wordMap[k].append(s) + + def mapKeys(self, s: str) -> List[str]: + return [s[:i] + "*" + s[i + 1:] for i in range(len(s))] + + def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: + if not endWord in wordList: + return 0 + + self.buildMap(set([beginWord] + wordList)) + + queue = collections.deque([(beginWord, 1)]) + seen = set([beginWord]) + while queue: + current, step = queue.popleft() + if current == endWord: + return step + + for k in self.mapKeys(current): + words = self.wordMap[k] + for w in words: + if not w in seen: + seen.add(w) + queue.append((w, step + 1)) + return 0 \ No newline at end of file diff --git a/week04/200_number_of_islands.py b/week04/200_number_of_islands.py new file mode 100644 index 00000000..4a006e8e --- /dev/null +++ b/week04/200_number_of_islands.py @@ -0,0 +1,29 @@ +class Solution: + def __init__(self): + self.grid = None + self.m = 0 + self.n = 0 + + def dfsMarking(self, i: int, j: int): + if i < 0 or i >= self.m or j < 0 or j >= self.n or self.grid[i][j] == "0": + return + + self.grid[i][j] = "0" + self.dfsMarking(i, j + 1) + self.dfsMarking(i, j - 1) + self.dfsMarking(i + 1, j) + self.dfsMarking(i - 1, j) + + def numIslands(self, grid: List[List[str]]) -> int: + if not grid or not grid[0]: + return 0 + + count = 0 + self.grid, self.m, self.n = grid, len(grid), len(grid[0]) + for i in range(self.m): + for j in range(self.n): + if grid[i][j] == "1": + count += 1 + self.dfsMarking(i, j) + + return count \ No newline at end of file diff --git a/week04/455_assign_cookies.py b/week04/455_assign_cookies.py new file mode 100644 index 00000000..f0a864eb --- /dev/null +++ b/week04/455_assign_cookies.py @@ -0,0 +1,13 @@ +class Solution: + def findContentChildren(self, g: List[int], s: List[int]) -> int: + g, s = sorted(g), sorted(s) + lg, ls = len(g), len(s) + count, i, j = 0, 0, 0 + while i < lg and j < ls: + if g[i] > s[j]: + j += 1 + else: + count += 1 + i += 1 + j += 1 + return count \ No newline at end of file diff --git a/week04/529_minesweeper.py b/week04/529_minesweeper.py new file mode 100644 index 00000000..d372ccbb --- /dev/null +++ b/week04/529_minesweeper.py @@ -0,0 +1,43 @@ +class Solution: + def __init__(self): + self.board = None + self.m = None + self.n = None + self.directions = [(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1)] + + def isOutOfBound(self, x: int, y: int) -> bool: + return x < 0 or x >= self.m or y < 0 or y >= self.n + + def hasMine(self, x: int, y: int) -> bool: + return not self.isOutOfBound(x, y) and self.board[x][y] == "M" + + def adjacentMine(self, x: int, y: int) -> int: + count = 0 + for dx, dy in self.directions: + count += self.hasMine(x + dx, y + dy) + return count + + def revealBoard(self, x: int, y: int): + if self.isOutOfBound(x, y) or not self.board[x][y] in ("M", "E"): + return + + # mine, reveal and return + if self.board[x][y] == "M": + self.board[x][y] = "X" + return + + # has adjacent mines, mark number and return + count = self.adjacentMine(x, y) + if count: + self.board[x][y] = str(count) + return + + # blank field, mark and reveal adjacent grids + self.board[x][y] = "B" + for dx, dy in self.directions: + self.revealBoard(x + dx, y + dy) + + def updateBoard(self, board: List[List[str]], click: List[int]) -> List[List[str]]: + self.board, self.m, self.n = board, len(board), len(board[0]) + self.revealBoard(*click) + return self.board \ No newline at end of file diff --git a/week04/55_jump_game.py b/week04/55_jump_game.py new file mode 100644 index 00000000..c00448e0 --- /dev/null +++ b/week04/55_jump_game.py @@ -0,0 +1,9 @@ +class Solution: + def canJump(self, nums: List[int]) -> bool: + # mark the point from where can get to the end + length = len(nums) + mark = length - 1 + for i in range(length - 2, -1, -1): + if i + nums[i] >= mark: + mark = i + return mark == 0 diff --git a/week04/860_lemonade_change.py b/week04/860_lemonade_change.py new file mode 100644 index 00000000..9efeb5c3 --- /dev/null +++ b/week04/860_lemonade_change.py @@ -0,0 +1,15 @@ +class Solution: + def lemonadeChange(self, bills: List[int]) -> bool: + d = {5: 0, 10: 0} + for b in bills: + if b == 5: + d[5] += 1 + elif b == 10: + d[5], d[10] = d[5] - 1, d[10] + 1 + elif d[10] > 0: + d[5], d[10] = d[5] - 1, d[10] - 1 + else: + d[5] -= 3 + if d[5] < 0: + return False + return True \ No newline at end of file diff --git a/week04/874_walking_robot_simulation.py b/week04/874_walking_robot_simulation.py new file mode 100644 index 00000000..8bd5eb05 --- /dev/null +++ b/week04/874_walking_robot_simulation.py @@ -0,0 +1,21 @@ +class Solution: + def robotSim(self, commands: List[int], obstacles: List[List[int]]) -> int: + dirs = [(0, 1), (1, 0), (0, -1), (-1, 0)] + loc, di = [0, 0], 0 + s = set(map(tuple, obstacles)) + res = 0 + + for c in commands: + if c == -2: + di = (di - 1 + 4) % 4 + if c == -1: + di = (di + 1) % 4 + else: + for i in range(c): + if (loc[0] + dirs[di][0], loc[1] + dirs[di][1]) in s: + break + else: + loc[0] = loc[0] + dirs[di][0] + loc[1] = loc[1] + dirs[di][1] + res = max(res, loc[0] * loc[0] + loc[1] * loc[1]) + return res \ No newline at end of file From 1c0850d9e919643a43b104e4060bcdd1bbaa6398 Mon Sep 17 00:00:00 2001 From: arichen Date: Mon, 16 Nov 2020 21:02:45 -0800 Subject: [PATCH 11/20] note and more problem --- week04/126_word_ladder_II.py | 21 +++++++++++++++++++++ week04/NOTE.md | 10 +++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 week04/126_word_ladder_II.py diff --git a/week04/126_word_ladder_II.py b/week04/126_word_ladder_II.py new file mode 100644 index 00000000..f2fe8e42 --- /dev/null +++ b/week04/126_word_ladder_II.py @@ -0,0 +1,21 @@ +class Solution: + def findLadders(self, beginWord: str, endWord: str, wordList: List[str]) -> List[List[str]]: + letters = [chr(ord("a") + i) for i in range(26)] + + end = collections.defaultdict(list) # map of (end word: list of word sequence) + end[beginWord] = [[beginWord]] + available = set(wordList) + while end: + temp = collections.defaultdict(list) + for w in end: + if w == endWord: + return end[w] + + for i in range(len(w)): + for c in letters: + w2 = w[:i] + c + w[i + 1:] + if w2 != w and w2 in available: + temp[w2] += [l + [w2] for l in end[w]] + available -= set(temp.keys()) + end = temp + return [] \ No newline at end of file diff --git a/week04/NOTE.md b/week04/NOTE.md index 50de3041..b0cb90e0 100644 --- a/week04/NOTE.md +++ b/week04/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file +## Binary Search +- Answer why a problem can be solved by binary search: increasing/decreasing, bounded. + +## Note +- trick +```python +(left + right) // 2 # may overflow +left + (right - left) // 2 # preven overflow when values are large +``` \ No newline at end of file From 7eb2a7fa0188f3ac3b30fdad678b197364b9ab89 Mon Sep 17 00:00:00 2001 From: arichen Date: Mon, 16 Nov 2020 22:44:05 -0800 Subject: [PATCH 12/20] notes --- week04/NOTE.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/week04/NOTE.md b/week04/NOTE.md index b0cb90e0..9c15cadd 100644 --- a/week04/NOTE.md +++ b/week04/NOTE.md @@ -1,8 +1,11 @@ ## Binary Search - Answer why a problem can be solved by binary search: increasing/decreasing, bounded. +## Problem: Find Minimum in Rotated Sorted Array +https://github.com/arichen/algorithm-notes/blob/main/binary_search/minimum_in_rotated_sorted_array.md + ## Note -- trick +- half.. ```python (left + right) // 2 # may overflow left + (right - left) // 2 # preven overflow when values are large From bd1735dd439111721e64d599fb4f3ce866b5079c Mon Sep 17 00:00:00 2001 From: arichen Date: Tue, 17 Nov 2020 16:02:35 -0800 Subject: [PATCH 13/20] homework 04 supplement --- week04/153_minimum_rotated_sorted_array.py | 13 ++++++++++ week04/33_search_rotated_sorted_array.py | 29 ++++++++++++++++++++++ week04/74_search_2d_matrix.py | 18 ++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 week04/153_minimum_rotated_sorted_array.py create mode 100644 week04/33_search_rotated_sorted_array.py create mode 100644 week04/74_search_2d_matrix.py diff --git a/week04/153_minimum_rotated_sorted_array.py b/week04/153_minimum_rotated_sorted_array.py new file mode 100644 index 00000000..804fb678 --- /dev/null +++ b/week04/153_minimum_rotated_sorted_array.py @@ -0,0 +1,13 @@ +class Solution: + def findMin(self, nums: List[int]) -> int: + if nums[0] <= nums[-1]: + return nums[0] + + left, right = 0, len(nums) - 1 + while left + 1 < right: + mid = left + (right - left) // 2 + if nums[left] <= nums[mid]: + left = mid + else: + right = mid + return nums[right] \ No newline at end of file diff --git a/week04/33_search_rotated_sorted_array.py b/week04/33_search_rotated_sorted_array.py new file mode 100644 index 00000000..9f9ed192 --- /dev/null +++ b/week04/33_search_rotated_sorted_array.py @@ -0,0 +1,29 @@ +class Solution: + def search(self, nums: List[int], target: int) -> int: + low, high = 0, len(nums) - 1 + + # use <= because we want to search all candidates + while low <= high: + mid = low + (high - low) // 2 + + if nums[mid] == target: + return mid + + if nums[mid] <= nums[high]: + # array is increasing at right side, pivot point is at left side + if nums[mid] < target <= nums[high]: + # if target value falls between nums[mid] and nums[high], + # then it must be between (mid, high], otherwise it's not found + low = mid + 1 + else: + # otherwise, the target value might be at the left side + high = mid - 1 + else: + # array wraps around at right side, pivot point is at the right + if nums[mid] < target or target <= nums[high]: + # target value will be right side, otherwise it's not found + low = mid + 1 + else: + # otherwise, search the left side + high = mid - 1 + return -1 \ No newline at end of file diff --git a/week04/74_search_2d_matrix.py b/week04/74_search_2d_matrix.py new file mode 100644 index 00000000..34efdc50 --- /dev/null +++ b/week04/74_search_2d_matrix.py @@ -0,0 +1,18 @@ +class Solution: + def searchMatrix(self, matrix: List[List[int]], target: int) -> bool: + if not matrix or not matrix[0]: + return False + + row, col = len(matrix), len(matrix[0]) + low, high = 0, row * col - 1 + while low <= high: + mid = low + (high - low) // 2 + r, c = (mid // col), (mid % col) + + if matrix[r][c] == target: + return True + if matrix[r][c] < target: + low = mid + 1 + else: + high = mid - 1 + return False \ No newline at end of file From a36558e8277d4fbf4561cd9d9b7704f6b71ab9eb Mon Sep 17 00:00:00 2001 From: arichen Date: Tue, 17 Nov 2020 22:51:32 -0800 Subject: [PATCH 14/20] homeword04 supplement --- week04/45_jump_game_II.py | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 week04/45_jump_game_II.py diff --git a/week04/45_jump_game_II.py b/week04/45_jump_game_II.py new file mode 100644 index 00000000..aeeb4f47 --- /dev/null +++ b/week04/45_jump_game_II.py @@ -0,0 +1,26 @@ +class Solution: + def jump(self, nums: List[int]) -> int: + # algorithm: bfs search for shortest path to the end + # 1. start with first element, find the farthest location we can reach from it, which is nums[0]. + # 2. the range we can reach for the next jump would then be (1, nums[0]], + # scan through the elements and find the farthest reachable location in next jump. + # 3. repeat for the next jump + + steps = 0 + start, end, n = 0, 0, len(nums) + + # when end reaches (n - 1), it reaches our destination + while end < n - 1: + steps += 1 + # increase step count by 1 at each loop + + next_end = end + # next_end will be the new ending boundary for next level + + for i in range(start, end + 1): + next_end = max(i + nums[i], next_end) + # look for the farthest location that can be reached from this level + + start = end + 1 + end = next_end + return steps \ No newline at end of file From 5e0f9bd4c0bff2846687ed41bbdf7c18329567f1 Mon Sep 17 00:00:00 2001 From: arichen Date: Mon, 30 Nov 2020 00:11:23 -0800 Subject: [PATCH 15/20] homework 06 --- week06/64_minimum_path_sum.py | 16 ++++++++++++++++ week06/91_decode_ways.py | 21 +++++++++++++++++++++ week06/NOTE.md | 5 ++++- 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 week06/64_minimum_path_sum.py create mode 100644 week06/91_decode_ways.py diff --git a/week06/64_minimum_path_sum.py b/week06/64_minimum_path_sum.py new file mode 100644 index 00000000..32119f8d --- /dev/null +++ b/week06/64_minimum_path_sum.py @@ -0,0 +1,16 @@ +# Idea: +# Each grid can only be reached from top or left grid. +# The minimum path to a grid must come from either top or left grid. +# +# Subproblem (roughly): f(i, j) = min(f(top grid), f(left grid)) + grid(i, j) +class Solution: + def minPathSum(self, grid: List[List[int]]) -> int: + m, n = len(grid), len(grid[0]) + for i in range(1, m): + grid[i][0] += grid[i - 1][0] + for i in range(1, n): + grid[0][i] += grid[0][i - 1] + for i in range(1, m): + for j in range(1, n): + grid[i][j] += min(grid[i - 1][j], grid[i][j - 1]) + return grid[-1][-1] \ No newline at end of file diff --git a/week06/91_decode_ways.py b/week06/91_decode_ways.py new file mode 100644 index 00000000..5ed68fed --- /dev/null +++ b/week06/91_decode_ways.py @@ -0,0 +1,21 @@ +# Idea: +# For each code, it can either be considered as single digit by itself, or double digit with previous code. +# If it can be considered single digit, use the number of ways up to previous code. +# If it can be considered as double digit, use the number of ways up to two letters before. +# +# Subproblem (roughly): f(n) = f(n-1) + f(n-2) +class Solution: + def numDecodings(self, s: str) -> int: + if not s: + return 0 + + a0, a1 = 1, 1 if int(s[0] != "0") else 0 + for i in range(1, len(s)): + temp = a1 if s[i] != "0" else 0 + + n = int(s[i - 1: i + 1]) + if n >= 10 and n <= 26: + temp += a0 + + a0, a1 = a1, temp + return a1 \ No newline at end of file diff --git a/week06/NOTE.md b/week06/NOTE.md index 50de3041..1899ac5d 100644 --- a/week06/NOTE.md +++ b/week06/NOTE.md @@ -1 +1,4 @@ -学习笔记 \ No newline at end of file +# Dynamic Programming +- "simplifying a complicated problem by breaking it down into simpler sub-problems in a recursive manner" (https://en.wikipedia.org/wiki/Dynamic_programming) +- Approach 1: Top Down (recursion + memorization) +- Approach 2: Bottom Up \ No newline at end of file From b0aee2c323db72b9b4931870ad6fcdf10918b562 Mon Sep 17 00:00:00 2001 From: arichen Date: Mon, 30 Nov 2020 01:01:00 -0800 Subject: [PATCH 16/20] homework 06 --- week06/221_maximal_square.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 week06/221_maximal_square.py diff --git a/week06/221_maximal_square.py b/week06/221_maximal_square.py new file mode 100644 index 00000000..db91763c --- /dev/null +++ b/week06/221_maximal_square.py @@ -0,0 +1,21 @@ +# Idea: +# If m[i][j] is 1, it can form square of smallest common sqaure length with m[i-1][j-1], m[i-1][j], m[i][j-1]. +# +# Subproblem: +# if m[i][j] == 1: +# f(i, j) = min(f(i-1, j-1), f(i-1, j), f(i, j-1)) + 1 +# else: +# f(i, j) = 0 +class Solution: + def maximalSquare(self, matrix: List[List[str]]) -> int: + m, n = len(matrix), len(matrix[0]) + dp = [[0] * (n + 1) for _ in range(m + 1)] + # add additional row and col to run through first row and col + + max_len = 0 + for i in range(1, m + 1): + for j in range(1, n + 1): + if matrix[i - 1][j - 1] == "1": + dp[i][j] = min(dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]) + 1 + max_len = max(dp[i][j], max_len) + return max_len * max_len \ No newline at end of file From 07c150d84eb25409d397e1f41d512ddea9eefe31 Mon Sep 17 00:00:00 2001 From: arichen Date: Mon, 30 Nov 2020 23:10:50 -0800 Subject: [PATCH 17/20] more homework06 --- week06/621_task_scheduler.py | 23 +++++++++++++++++++++++ week06/647_palindromic_substrings.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 week06/621_task_scheduler.py create mode 100644 week06/647_palindromic_substrings.py diff --git a/week06/621_task_scheduler.py b/week06/621_task_scheduler.py new file mode 100644 index 00000000..484009bd --- /dev/null +++ b/week06/621_task_scheduler.py @@ -0,0 +1,23 @@ +# Idea: +# The minimal total time is bound by the highest frequency task. +# +# e.g. n = 2, job A has highest frequency 5, the total time must be at least (5 - 1) * (2 + 1) + 1 = 13. +# Since there needs (5 - 1) cool down intervals between each task A. That creates 4 segments, each start with 1 unit time for A and followed by 2 idle unit time. The final task A doesn't need cool down time. +# +# e.g. n = 2, both job A and B have highest frequency 5. +# Start by considering job A, it needs 4 cool down intervals, at least 2 unit time each. +# Since job B needs the same amount of cool down time, placing B right after each A will work. +# The last job B must be after the last job A, therefore the last segment is 2 unit time. +# The minimal total time plan looks like "A..A..A..A..AB" +class Solution: + def leastInterval(self, tasks: List[str], n: int) -> int: + c = collections.Counter(tasks) + d = collections.defaultdict(list) + + f_max = 0 + for k, freq in c.items(): + d[freq] += [k] + f_max = max(freq, f_max) + n_max = len(d[f_max]) + + return max(len(tasks), (f_max - 1) * (n + 1) + n_max) \ No newline at end of file diff --git a/week06/647_palindromic_substrings.py b/week06/647_palindromic_substrings.py new file mode 100644 index 00000000..52877e69 --- /dev/null +++ b/week06/647_palindromic_substrings.py @@ -0,0 +1,28 @@ +# Idea: +# Each palindromic string is constitued by palindromic substring +# +# Subproblem: +# f(s(i,j)) = { +# True, if s[i] == s[j] and f(s(i+1, j-1)); +# False, otherwise +# } +class Solution: + def countSubstrings(self, s: str) -> int: + n = len(s) + dp = [[False] * n for _ in range(n)] + + # base case: length 1 + for i in range(n): + dp[i][i] = True + + # base case: length 2 + for i in range(1, n): + dp[i - 1][i] = (s[i - 1] == s[i]) + + # general case + for l in range(3, n + 1): # iterate through substring lengths + for i in range(n - l + 1): + j = i + l - 1 + dp[i][j] = (s[i] == s[j] and dp[i + 1][j - 1]) + + return sum([sum(r) for r in dp]) \ No newline at end of file From 85ff1c08f8dab2acddea4db60c7b9efe8591f120 Mon Sep 17 00:00:00 2001 From: arichen Date: Wed, 2 Dec 2020 00:23:50 -0800 Subject: [PATCH 18/20] more homework06 --- week06/32_longest_valid_parentheses.py | 21 +++++++++++++++++++++ week06/72_edit_distance.py | 26 ++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 week06/32_longest_valid_parentheses.py create mode 100644 week06/72_edit_distance.py diff --git a/week06/32_longest_valid_parentheses.py b/week06/32_longest_valid_parentheses.py new file mode 100644 index 00000000..4f73ce43 --- /dev/null +++ b/week06/32_longest_valid_parentheses.py @@ -0,0 +1,21 @@ +# Idea: +# Each valid parentheses is consisted of other valid parentheses or empty string. +class Solution: + def longestValidParentheses(self, s: str) -> int: + dp = [0] * len(s) + max_len = 0 + for i in range(1, len(s)): + if s[i] == ")": + left = (i - 1) if not dp[i - 1] else (i - dp[i - 1] - 1) + # find the index where we should look for left bracket, + # which is the first position to the left that are not part of a closed parentheses. + + if left >= 0 and s[left] == "(": + # a left bracket found. close the parentheses. + + dp[i] = 2 + dp[i - 1] + (dp[left - 1] if left > 0 else 0) + # current local max length of valid parentheses is extended from previous max. + + max_len = max(dp[i], max_len) + # update global max length + return max_len \ No newline at end of file diff --git a/week06/72_edit_distance.py b/week06/72_edit_distance.py new file mode 100644 index 00000000..fe894744 --- /dev/null +++ b/week06/72_edit_distance.py @@ -0,0 +1,26 @@ +# Idea: +# Find the minimum diff of two strings +# +# Subproblem: +# min diff of word1[1..i] and word2[1..j] can be determined by +# f(w1[1..(i-1)], w2[1..j]), f(w1[1..i], w2[1..(j-1)]), f(w1[1..(i-1)], w2[1..(j-1)]) +class Solution: + def minDistance(self, word1: str, word2: str) -> int: + m, n = len(word1), len(word2) + dp = [[0] * (n + 1) for _ in range(m + 1)] + + # base case: + # first row and col is diff between empty string and word1 or word2 + for i in range(m + 1): + dp[i][0] = i + for i in range(n + 1): + dp[0][i] = i + + 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] = 1 + min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + + return dp[-1][-1] \ No newline at end of file From 43b0ddbf94258b33d74b5fcd9593c3bbfd31f26c Mon Sep 17 00:00:00 2001 From: arichen Date: Tue, 8 Dec 2020 01:03:28 -0800 Subject: [PATCH 19/20] homeword07 --- week07/208_trie.py | 47 ++++++++++++++++++++++++++++++++++ week07/212_word_search_II.py | 49 ++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 week07/208_trie.py create mode 100644 week07/212_word_search_II.py diff --git a/week07/208_trie.py b/week07/208_trie.py new file mode 100644 index 00000000..dc878ab3 --- /dev/null +++ b/week07/208_trie.py @@ -0,0 +1,47 @@ +class Trie: + + def __init__(self): + """ + Initialize your data structure here. + """ + self.root = {} + self.END_OF_WORD = "#" + + def insert(self, word: str) -> None: + """ + Inserts a word into the trie. + """ + node = self.root + for c in word: + node = node.setdefault(c, {}) + node[self.END_OF_WORD] = self.END_OF_WORD + + + def search(self, word: str) -> bool: + """ + Returns if the word is in the trie. + """ + node = self.root + for c in word: + node = node.get(c) + if not node: + return False + return self.END_OF_WORD in node + + def startsWith(self, prefix: str) -> bool: + """ + Returns if there is any word in the trie that starts with the given prefix. + """ + node = self.root + for c in prefix: + node = node.get(c) + if not node: + return False + return True + + +# Your Trie object will be instantiated and called as such: +# obj = Trie() +# obj.insert(word) +# param_2 = obj.search(word) +# param_3 = obj.startsWith(prefix) \ No newline at end of file diff --git a/week07/212_word_search_II.py b/week07/212_word_search_II.py new file mode 100644 index 00000000..4e167d26 --- /dev/null +++ b/week07/212_word_search_II.py @@ -0,0 +1,49 @@ +class Solution: + END_OF_WORD = "#" + VISITED = "-" + dx = [0, 1, 0, -1] + dy = [-1, 0, 1, 0] + + def __init__(self): + self.board = None + self.trie = None + self.rows = 0 + self.cols = 0 + self.result = set() + + def initTrie(self, words: List[str]): + self.trie = {} + for w in words: + node = self.trie + for c in w: + node = node.setdefault(c, {}) + node[self.END_OF_WORD] = self.END_OF_WORD + + def dfs(self, r: int, c: int, prefix: str, node: dict): + if not (0 <= r < self.rows and 0 <= c < self.cols and self.board[r][c] in node): + return + + prefix += self.board[r][c] + node = node[self.board[r][c]] + if self.END_OF_WORD in node: + self.result.add(prefix) + + tmp, self.board[r][c] = self.board[r][c], self.VISITED + for i in range(4): + self.dfs(r + self.dy[i], c + self.dx[i], prefix, node) + self.board[r][c] = tmp + + def initBoard(self, board: List[List[str]]): + self.board = board + self.rows = len(board) + self.cols = len(board[0]) + + def findWords(self, board: List[List[str]], words: List[str]) -> List[str]: + self.initTrie(words) + self.initBoard(board) + + self.result = set() + for i in range(self.rows): + for j in range(self.cols): + self.dfs(i, j, "", self.trie) + return self.result From d1f46fc08fd16d6f23913d106c044925f2c5b0ec Mon Sep 17 00:00:00 2001 From: arichen Date: Sat, 12 Dec 2020 23:49:46 -0800 Subject: [PATCH 20/20] homework08 --- week08/1122_relative_sort.py | 7 ++++ week08/1244_leaderboard.py | 23 ++++++++++++ week08/146_lru_cache.py | 68 ++++++++++++++++++++++++++++++++++ week08/190_reverse_bits.py | 7 ++++ week08/191_number_of_1_bits.py | 8 ++++ week08/231_power_of_two.py | 4 ++ week08/242_valid_anagram.py | 4 ++ week08/56_merge_intervals.py | 11 ++++++ week08/NOTE.md | 10 ++++- 9 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 week08/1122_relative_sort.py create mode 100644 week08/1244_leaderboard.py create mode 100644 week08/146_lru_cache.py create mode 100644 week08/190_reverse_bits.py create mode 100644 week08/191_number_of_1_bits.py create mode 100644 week08/231_power_of_two.py create mode 100644 week08/242_valid_anagram.py create mode 100644 week08/56_merge_intervals.py diff --git a/week08/1122_relative_sort.py b/week08/1122_relative_sort.py new file mode 100644 index 00000000..d06d144a --- /dev/null +++ b/week08/1122_relative_sort.py @@ -0,0 +1,7 @@ +# Idea: +# Use the array.index function as the sorting key. +# Combine arr2 and sorted arr1, so the overlapping elements will use index of arr2, +# and non-overlapping elements will be in acsending order. +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + return sorted(arr1, key=(arr2 + sorted(arr1)).index) \ No newline at end of file diff --git a/week08/1244_leaderboard.py b/week08/1244_leaderboard.py new file mode 100644 index 00000000..d3d57fd3 --- /dev/null +++ b/week08/1244_leaderboard.py @@ -0,0 +1,23 @@ +# idea: lazy sort, only sort when top() is called +# use heapq to return K largest elements + +class Leaderboard: + + def __init__(self): + self.scores = collections.defaultdict(int) + + def addScore(self, playerId: int, score: int) -> None: + self.scores[playerId] += score + + def top(self, K: int) -> int: + return sum(heapq.nlargest(K, self.scores.values())) + + def reset(self, playerId: int) -> None: + del self.scores[playerId] + + +# Your Leaderboard object will be instantiated and called as such: +# obj = Leaderboard() +# obj.addScore(playerId,score) +# param_2 = obj.top(K) +# obj.reset(playerId) \ No newline at end of file diff --git a/week08/146_lru_cache.py b/week08/146_lru_cache.py new file mode 100644 index 00000000..1cef1a3d --- /dev/null +++ b/week08/146_lru_cache.py @@ -0,0 +1,68 @@ +# Use hashmap + double linked list + +class Node: + def __init__(self, key: int = None, value: int = None, next: "Node" = None, prev: "Node" = None): + self.key = key + self.value = value + self.next = next + self.prev = prev + +class LRUCache: + + def __init__(self, capacity: int): + self.capacity = capacity + self.map = {} # map the keys to node + self.head = Node() + self.tail = Node() + + self.head.next = self.tail + self.tail.prev = self.head + + def get(self, key: int) -> int: + node = self.map.get(key) + if not node: + return -1 + self._move_to_head(node) + return node.value + + def put(self, key: int, value: int) -> None: + node = self.map.get(key) + + if not node: + node = Node(key, value) + self.map[key] = node + + self._push_node(node) + if len(self.map) > self.capacity: + tail = self._pop_tail() + del self.map[tail.key] + else: + node.value = value + self._move_to_head(node) + + def _push_node(self, node): + # fix the head node, always add right after head + node.prev = self.head + node.next = self.head.next + + self.head.next.prev = node + self.head.next = node + + def _pop_tail(self): + # fix the tail node, always pop the node before tail + node = self.tail.prev + self._remove_node(node) + return node + + def _remove_node(self, node): + node.prev.next = node.next + node.next.prev = node.prev + + def _move_to_head(self, node): + self._remove_node(node) + self._push_node(node) + +# Your LRUCache object will be instantiated and called as such: +# obj = LRUCache(capacity) +# param_1 = obj.get(key) +# obj.put(key,value) \ No newline at end of file diff --git a/week08/190_reverse_bits.py b/week08/190_reverse_bits.py new file mode 100644 index 00000000..ec34ccd9 --- /dev/null +++ b/week08/190_reverse_bits.py @@ -0,0 +1,7 @@ +class Solution: + def reverseBits(self, n: int) -> int: + res = 0 + for i in range(32): + res += (n & 1) << (32 - i - 1) + n >>= 1 + return res \ No newline at end of file diff --git a/week08/191_number_of_1_bits.py b/week08/191_number_of_1_bits.py new file mode 100644 index 00000000..619c8c22 --- /dev/null +++ b/week08/191_number_of_1_bits.py @@ -0,0 +1,8 @@ +# n & (n - 1): flips the least significant 1-bit to 0 +class Solution: + def hammingWeight(self, n: int) -> int: + count = 0 + while n > 0: + count += 1 + n &= n - 1 + return count \ No newline at end of file diff --git a/week08/231_power_of_two.py b/week08/231_power_of_two.py new file mode 100644 index 00000000..3df063e5 --- /dev/null +++ b/week08/231_power_of_two.py @@ -0,0 +1,4 @@ +# n & (n - 1): flips the least significant 1-bit to 0 +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return (n > 0) and (n & (n - 1) == 0) \ No newline at end of file diff --git a/week08/242_valid_anagram.py b/week08/242_valid_anagram.py new file mode 100644 index 00000000..50a683df --- /dev/null +++ b/week08/242_valid_anagram.py @@ -0,0 +1,4 @@ +from collections import Counter +class Solution: + def isAnagram(self, s: str, t: str) -> bool: + return Counter(s) == Counter(t) \ No newline at end of file diff --git a/week08/56_merge_intervals.py b/week08/56_merge_intervals.py new file mode 100644 index 00000000..e373a8e7 --- /dev/null +++ b/week08/56_merge_intervals.py @@ -0,0 +1,11 @@ +class Solution: + def merge(self, intervals: List[List[int]]) -> List[List[int]]: + intervals = sorted(intervals, key=lambda x: x[0]) + + res = [] + for interval in intervals: + if not res or res[-1][1] < interval[0]: + res.append(interval) + else: + res[-1][1] = max(res[-1][1], interval[1]) + return res \ No newline at end of file diff --git a/week08/NOTE.md b/week08/NOTE.md index 50de3041..506c84c6 100644 --- a/week08/NOTE.md +++ b/week08/NOTE.md @@ -1 +1,9 @@ -学习笔记 \ No newline at end of file +## Bit Operation +- Odd and even + - odd: x & 1 == 1 + - even: x & 1 == 0 +- Divide by 2: + - x >> 1 + - bit operation is faster than division +- x & (x - 1): flip the least significant 1-bit to 0 +- x & -x: get the lowest bit 1 \ No newline at end of file