---
# System prepended metadata

title: Info2023-homework2

---

# Info2023-homework2
# 模擬面試
貢獻者：迪奧 Dio
[video](https://youtu.be/ef43Yj8wvzk)

interviewer:🥵
interviewee:😈

🥵：我們是一家AI的新創公司，在我們研發部門目前有建立幾個模組需要測試他們的準確度，還有和其他模組搭配的成效如何。因此，我們希望同學可以幫我們排出這些模組的可能性。當我們給予`n`個模組，還有一組需要`k`個模組的時候。

😈：好的。所以您的意思是，當我們現在有`n`個模組，需要一次取出`k`個模組時，排出他們的可能性。

🥵：對。

😈：舉例來說當 n = 4，k = 2，這樣可排出這樣嗎？
```
[1, 2][1, 3][1, 4]
[2, 3][2, 4]
[3, 4]
```

🥵：對。就是這樣。

😈：好的。那如何有效排出這個算法，我覺得可以使用dfs深度優先演算法來解決這樣的問題。

🥵：為什麼是dfs，而不是bfs呢？可以請你解釋一下嗎？

😈：好的。我們可以把這個排列的問題想像成一棵樹狀結構。以這個 n = 4，k = 2來舉例的話，我們可以從樹的根節點往下有1、2、3的節點。

😈：我們先從1的節點往下可以走到2，然後發現 [1, 2] 的combination可以達到 k = 2 的條件。所以就回傳它，然後回去1這個節點再往下發現3這個節點。然後發現 [1, 3] 這個組合完成 k = 2 的條件。所以說又把3給pop掉，回到1。

😈：繼續延伸找到4，[1, 4]這個組合也同樣達到條件以後，再回去1這個節點。然後發現1下面的234已經走完了。所以從1再回去根節點來到2，依序走完[2, 3] [2, 4]。最後到[3, 4]。

😈：那他就是一個深度優先演算法。我們先走到最深後，再往回看有沒有其他路可以走。

😈：而bfs則是廣度優先演算法，那他則是有點像是波紋擴散。會把1同樣層級的234一起搜尋到後，在繼續擴散到他們的子節點。這樣就不符合我們搜尋的方式。

😈：所以說我們這個應該使用dfs的算法。而照我剛剛的講法，他其實蠻適合使用遞迴的方式來解決。

🥵：ok。那可以請你撰寫程式碼來實作你的想法嗎？

😈：好的我現在馬上使用python code來實作。首先，定義一個combination的function。那我把它取名叫做combine，他需要有n和k兩個參數。而我們需要一個回傳的list。所以我們把回傳的list給定義好了之後。

😈：接著我們來建立dfs function。根據我剛剛的說法，他需要一個⋯⋯我們需要依序把點加入到combination當中，然後根據combination和加入的點來判斷他現在是不是已經達成長度等於k的條件。

😈：如果是的話，就把comb加入res當中。要注意的是需要把它copy一份加入進去，而不是直接把combination加入進去。因為，在操作當中會重複使用comb，如果這時候冒然把還不是最終答案的comb加入進去的話，那很容易導致後續發生錯誤。

😈：接著，當comb長度未達k時，我們要持續把點加入combination當中，所以我們需要for回圈。從start point開始到n+1。

😈：為什麼是n+1呢？因為range 是取頭不取尾，所以使用n+1才可以把尾也考慮進去。而在for回圈當中，首先要做的事情是在comb當中去 append第i個點，也就是從start開始，到n+1加入到comb中。加完之後，使用dfs演算法來判斷是否這次加完之後長度就夠了。

😈：足夠的話，就把comb加入res當中，若不足的話，又會繼續加入下個點進來。當把一種組合都加完後，我們會把最後加入的給pop出去，讓他可以持續加入新的組合進來。

😈：完成dfs演算法之後，我們可以從1 start point開始，搭配空的res list開始。最後，就可以return res。

🥵：那可以請你舉例一下嗎？

😈：好那一樣使用 n = 4，k = 2 來舉例。當dfs一開始從1和空的傳入，因為發現comb長度不為k，所以會加入點i，也就是1。

😈：接著進入dfs，變成dfs(2,  [1])。接著，因為又進入第二次dfs，且comb長度仍未達k，所以又進去for loop中，加入2的點成為comb: [1, 2] 然後到dfs算法當中dfs(3, [1, 2])。

😈：這時發現comb長度等於k，所以把comb給append到res當中。然後將最後的值pop出去，回到for loop加入3，然後依序執行dfs和pop。

😈：就會發現它持續把[1, 2][1, 3][1, 4][2, 3][2, 4]最後[3, 4]找到。這樣他就完成找到n = 4，k = 2的方式。

```python=
def combine(n , k):
	res = []

	def dfs(start, comb):
		if len(comb) == k:
			res.append(comb.copy())
		else:
			for i in range(start, n+1):
				comb.append(i)
				dfs(i + 1, comb)
				comb.pop()
	dfs(1, [])
	return res

```

🥵：ok。你的演算法和舉例已經非常完善。但是，當使用遞迴方式時，如果今天要排列的數非常大，那就代表遞迴需要重複呼叫許多次。那可能電腦記憶體不足。所以有沒有其他的方式，不使用遞迴重複呼叫的方式來完成？

😈：恩，有的。如果不使用遞迴的方式時，我覺得可以使用stack來儲存遞迴時所需的東西。而程式碼大概可以是combine⋯⋯不好意思，口有點渴，喝口水。

😈：我的想法是說，可以使用stack來取代遞迴的方式。也就是持續把點和comb append到stack當中。美次去檢查start point和comb。如果長度夠的話，就把comb append 到 res list當中。其他時候就是持續加入到stack當中。差不多是這樣子的想法。

🥵：好，請你繼續實作。

😈：ok。同樣一開始需要result list儲存結果。因為使用stack所以定義一個stack。接著，當stack非空，每次我們會把start和comb從stack中pop出，讓我們可以去檢查長度是否足夠。

😈：若足夠則res.append(comb.copy())，其他時候就for i in range(start, n + 1)把comb append到 stack當中。這裡使用comb + [i]只是方便寫而已，當然也可以使用comb.append(i)。

😈：最後，return res。那我們可以直接在stack當中加入第一種組合，這樣就可以簡潔程式碼同時達成while stack非空的條件。

```python=
def combine(n, k):
	res = []
	stack = [(1, [])]
	
	while stack:
	start, comb = stack.pop()
	if len(comb) == k:
		res.append(comb.copy())

	for i in range(start, n + 1):
		stack.append((i + 1, comb + [i]))

return res

```

🥵：ok，我理解你程式碼運作的原理及想法。這樣子的實作已經很完善。另外，我想問這兩種演算法，哪種時間複雜度比較好，哪種空間複雜度比較好呢？

😈：首先看到第一個演算法，因為他使用dfs他的時間複雜度是O(Cn取k)，空間複雜度因為使用到一個list操作comb因此是O(k)。

😈：而不使用遞迴的方式，他的空間複雜度一樣操作在comb所以是O(k)，時間複雜度則是O(Cn取k)。因為，每次都會把東西append到comb當，所以是取決在Cn取k的上面。

🥵：好哦。看來你知道這兩種演算法的時間、空間複雜度是一樣。只是差在是否遞迴，而使用stack的方式可以解決當數字很大時，遞迴可能造成記憶體不足的問題。

😈：是的。

🥵：這次的inerview就到這裡。謝謝你。

😈：謝謝。


總共評論五位：
1. [布撥 Pawmi](https://hackmd.io/@sysprog/S1ZLuL616)
2. [呆呆獸 Slowpoke](https://hackmd.io/@sysprog/Sy2E1d6yp)
3. [牙塑 Wind](https://hackmd.io/@sysprog/r1JYgOakp)
4. [瑪奇朵 Macchiato](https://hackmd.io/@sysprog/r1WoJGleT)
5. [奧黛麗 Audrey](https://hackmd.io/@sysprog/rJ5V1Ip16)

# 簡介對同儕評論
## [布撥 Pawmi](https://hackmd.io/@sysprog/S1ZLuL616)
- **優點**：聲音溫和好聽、第2, 3題interviewer和interviewee的互動性蠻好的，有來有往。
- **可改進的地方**：雜音很多、聲音可以更加強壯與抑揚頓挫來提升自信心和吸引人、邊打程式碼時應該邊解釋。

## [呆呆獸 Slowpoke](https://hackmd.io/@sysprog/Sy2E1d6yp)
- **優點**：說明自己的想法後再開始實作。
- **可改進的地方**：打字有異音很躁、聲音可以增加抑揚頓挫會更吸引人、邊打程式碼時應該同時解釋，不然打很慢、又很安靜。

## [牙塑 Wind](https://hackmd.io/@sysprog/r1JYgOakp)
- **優點**：說明python底層邏輯讓interviewer眼睛為之一亮，也明白你是有料的。此外，撰寫程式碼時邊說明用途，邏輯也非常清晰有條理。
- **可改進的地方**：當interviewee提出一些做法時，interviewer可以提出質疑使interviewee思考，並說明自己的看法。這樣interviewer可以更加理解interviewee是不是真的理解。

## [瑪奇朵 Macchiato](https://hackmd.io/@sysprog/r1WoJGleT)
- **優點**：詳細說明程式的演算法優缺點、打程式碼邊解說。
- **可改進的地方**：使用情境題來包裝leetcode原題、聲音有時候變很小聲。

## [奧黛麗 Audrey](https://hackmd.io/@sysprog/rJ5V1Ip16)
- **優點**：英文好聽、部分題目有用情境帶入。
- **可改進的地方**：interviewer可以引導interviewee做更多的延伸，以及適時質疑interviewee讓他思考。

# 我所學習到的點
## interviewer
- 避免直接使用leetcode原題。配合公司方向的情境題會更好。
- 適時地質疑interviewee來確認他是否真的理解亦或是背答案。
- 引導interviewee說明自己的看法。

## interviewee
- 先清楚說明自己的想法後再開始實作。
- 聲音要更有自信與抑揚頓挫，才更能展現個人自信心與魅力。
- 說明自己的做法有哪些優缺點。