# info2021-homework1 暱稱:滿天星/Stars ## 針對 interviewer 的檢討 + 專注在討論時間複雜度,忽略空間複雜度的討論 + 沒有引導 interviewee 針對特殊 case 做更詳細的討論 + 在說明題意時太冗、沒有用更直白的方法描述題目需求 + 直接接受 interviewee 的答案,沒有多做提問 + 要求 interviewer 提出更好的作法,但沒有說清楚「好」的意思是什麼 + 英語能力不夠好 ## 針對 interviewee 的檢討 + 沒有提及空間複雜度 + 沒有針對特殊 case 做更多提問,導致寫出來的程式碼可能會在極端案例中出錯 + 一開始錄的時候忘記補上遞迴的終止條件 + [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) 邊說明想法就邊開始寫程式碼了,但應該先跟 interviewer 討論,確定要採用這個方案再開始寫程式碼 <br/> # Homework 1 ### 第一題 Two sum (Leetcode 1) 題目要求: > Given an array of integers `nums` and an integer `target`, return indices of the two numbers such that they add up to `target`. > <br/>You may assume that each input would have exactly one solution, and you may not use the same element twice. > <br/>You can return the answer in any order. 一開始的做法 ```python= def twoSum(self, nums, target) : global x,y n = len(nums) for i in range(n): for j in range(i+1,n):#n-i-1 if nums[i]+nums[j] == target: x = i y = j break return x, y ``` 使用 two for loop 實作,兩兩確認是否相加為 target,時間複雜度O(n^2^) <br/> O(n) 的做法 ```python= def twoSum(self, nums: List[int], target: int) -> List[int]: hashmap = {} for i in range(len(nums)): complement = target - nums[i] if nums[i] in hashmap: return [hashmap[nums[i]], i] hashmap[complement] = i ``` 利用 hashmap 查詢只要 O(1) 的特性,將 complement 存至 hashmap,並一一確認是否為先前的 complement,時間複雜度 O(n) <br/> ### 第二題 Binary Tree Inorder Traversal (Leetcode 94) 題目要求: > Given the `root` of a binary tree, return the inorder traversal of its nodes' values. 一開始的做法 ```python= def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: if root == None: return [] l = self.inorderTraversal(root.left) r = self.inorderTraversal(root.right) l.append(root.val) if r: l.extend(r) return l ``` 使用 recursive 的方式,把左子、現在的 node、右子串再一起回傳即可 <br/> 更改為 iterative 的做法 ```python= def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: stack = [] ans = [] while stack or root: while root: stack.append(root) root = root.left root = stack.pop() ans.append(root.val) root = root.right return ans ``` 使用 stack 的方式,依照先前 recursive 的順序將 node 推進 stack 裡面,直到不能推(沒有右子)的時候,再將 node 從 stack 裡面 pop 出來 <br/> ### 第三題 Jump Game (Leetcode 55) 題目要求: > You are given an integer array `nums`. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.<br/> > Return `true` if you can reach the last index, or `false` otherwise. 一開始的做法 ```python= def canJump(self, nums: List[int]) -> bool: n = len(nums) aux = [0 for i in range(n)] aux[0] = 1 for i in range(n): if aux[i] == 0: return False for j in range(1, nums[i]+1): if i + j < n: aux[i+j] = 1 return True ``` 相當直覺的做法,依照每個元素的大小向後做標記,如果走到未經標記的位置(0)則 return False,反之如果一路走到最後,則 return True,這樣做的時間複雜度是O(m*n),m 為元素的平均大小,n 為元素個數 <br/> 只需要O(n)的做法 ```python= def canJump(self, nums: List[int]) -> bool: n = len(nums) farthest = 0 for i in range(n): if i + nums[i] > farthest: farthest = i + nums[i] elif i == farthest and i != n - 1: return False return farthest >= n - 1 ``` 每次記錄可以走的最遠距離,一但超過最遠距離則 return False,否則確認當下元素的大小,到能不能走得更遠,若走到最後則 return True,因為只要每個元素都走過一遍,時間複雜度只需要O(n),且不需要額外的陣列做輔助 <br/> # Homework 2 ### 第一題 [94. Binary Tree Inorder Traversal](https://leetcode.com/problems/binary-tree-inorder-traversal/) 題目要求: > Given the `root` of a binary tree, return the inorder traversal of its nodes' values. 一開始的做法 ```python= def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: if root == None: return [] l = self.inorderTraversal(root.left) r = self.inorderTraversal(root.right) l.append(root.val) if r: l.extend(r) return l ``` 使用 recursive 的方式,把左子、現在的 node、右子串再一起回傳即可,與 interviewer 討論後,發現這樣的作法需要 O(n^2^) 的時間複雜度,故更改為 iterative 的做法 <br/> 更改為 iterative 的做法 ```python= def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: stack = [] ans = [] while stack or root: while root: stack.append(root) root = root.left root = stack.pop() ans.append(root.val) root = root.right return ans ``` 使用 stack 的方式,依照先前 recursive 的順序將 node 推進 stack 裡面,直到不能推(沒有右子)的時候,再將 node 從 stack 裡面 pop 出來 ### 變形題 [98. Validate Binary Search Tree](https://leetcode.com/problems/validate-binary-search-tree/) > Given the root of a binary tree, determine if it is a valid binary search tree (BST). 由於我們在上面的程式碼就是 inorder traversal,要拿來檢查一顆 BST 是否 valid,我們只需要確認每次造訪(被pop出來)的 node 的值是否愈來愈大 ```python= def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]: stack = [] tmp = float("-inf") while stack or root: while root: stack.append(root) root = root.left root = stack.pop() if tmp > root.val: return False tmp = root.val root = root.right return True ``` 所以多花一個 tmp 來儲存上一次造訪節點的值,並在每一次確認新的值是否更大(影片中的程式碼忘記加上 tmp 的初始化了,這邊有再補上),由於只多用到一個變數,時間與空間複雜度皆與前面程式碼相同 <br/> ### 第二題 [55. Jump Game](https://leetcode.com/problems/jump-game/) 題目要求: > You are given an integer array `nums`. You are initially positioned at the array's first index, and each element in the array represents your maximum jump length at that position.<br/> > Return `true` if you can reach the last index, or `false` otherwise. 一開始的做法 ```python= def canJump(self, nums: List[int]) -> bool: n = len(nums) aux = [0 for i in range(n)] aux[0] = 1 for i in range(n): if aux[i] == 0: return False for j in range(1, nums[i]+1): if i + j < n: aux[i+j] = 1 return True ``` 相當直覺的做法,依照每個元素的大小向後做標記,如果走到未經標記的位置(0)則 return False,反之如果一路走到最後,則 return True,這樣做的時間複雜度是O(m*n),m 為元素的平均大小,n 為元素個數 <br/> 只需要O(n)的做法 ```python= def canJump(self, nums: List[int]) -> bool: n = len(nums) farthest = 0 for i in range(n): if i + nums[i] > farthest: farthest = i + nums[i] elif i == farthest and i != n - 1: return False return farthest >= n - 1 ``` 每次記錄可以走的最遠距離,一但超過最遠距離則 return False,否則確認當下元素的大小,到能不能走得更遠,若走到最後則 return True,因為只要每個元素都走過一遍,時間複雜度只需要O(n),且不需要額外的陣列做輔助 ### 變形題 [45. Jump Game II](https://leetcode.com/problems/jump-game-ii/) > Your goal is to reach the last index in the minimum number of jumps. > You can assume that you can always reach the last index. 利用原來的程式碼,不同的地方在於,我們要用類似 checkpoint 的方式,checkpoint 是上次可以到達的最遠距離,每次到達 checkpoint 的時候會再把 checkpoint 更新成可以到達的最遠距離,同時 count + 1,如此一來,我們就能確保每次都跨出最遠的步伐,最後 return count 即可 ```python= def canJump(self, nums: List[int]) -> bool: n = len(nums) farthest = 0 curr = 0 count = 0 for i in range(n): if i + nums[i] > farthest: farthest = i + nums[i] if curr == i: count += 1 curr = farthest return count ``` <br/>