---
# System prepended metadata

title: info2021-homework1

---

# 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/>
