# 2025 年「資訊科技產業專案設計」作業 2 > 貢獻者: 周瑜 Zhou Yuuu, 伏爾泰 Voltaire 模擬面試影片 Leetcode .119 https://youtu.be/-65SRk0IXmQ 面試錄影 Leetcode .83 https://youtu.be/gX6slbtOdB8 ## [Leetcode 83.](https://leetcode.com/problems/remove-duplicates-from-sorted-list/description/) 🟦 Interviewer : 周瑜 Zhou Yuuu 🟨 Interviewee : 伏爾泰 Voltaire ### 面試過程 🟦:您好,今天面試的題目是刪除一個已排序的 List 中重複的數字,我會給你一個已排序的 Linked list 的 head,然後要刪除掉重複的數字,然後回傳這個被刪除重複數字的 linked list。 🟨:是 singly linked list 還是 doubly linked list? 🟦:是 singly linked list。 🟨:刪除重複的意思是?以 1->2->2->3 為例,是要刪除成 1->2->3 還是 1->3? 🟦:先刪除到所有數字都只出現一次。 🟨:是遞增還是遞減的排序? 🟦:是遞增的排序。 🟨:數字是 integer, 32 bits 的型態嗎? 🟦:是。 🟨:實作的話首先定義 node 的型態。然後舉一個例子,第一個 1->2->2->3 要刪除成 1->2->3,然後再舉一個例子顯示 edge case 情況,假設說 1->1->1->2->3->3,在這個情況下,總共會有兩個要刪除,1 跟 3 要刪除,變成 1->2->3。然後有個 edge case 是這個 linked list 只有一個節點,就不用處理直接回傳。 🟨:那我還想問 head 是一個指標嗎?還是 node 的型態。 🟦:對,是一個指標。 🟨:好,那 head 就是一個指標指向第一個節點嗎。 🟨:接下來我講一下我的解法,我會走訪 linked list,用一個指標指向目前正在走訪的這個節點,然後我們比較這個節點的數值和下一個節點的數值,若一樣,就刪除掉下一個節點,將上一個節點的指標指向下一個節點,然後繼續比對,如果比對到不一樣,就會遞推到下一個,繼續比對,跟剛剛一樣的邏輯,一樣就刪掉。 🟦:OK,聽起來沒有問題 🟨:那這個程式碼首先會回傳一個 head,輸入的參數也是一個 head。 ```c struct ListNode* deleteDuplicates(struct ListNode* head) { if (!head) return head; if (!head->next) return head; struct ListNode *curr = head, *dupli = NULL; while (curr != NULL && curr->next != NULL) { if (curr->val == curr->next->val) { dupli = curr->next; curr->next = curr->next->next; free(dupli); } else curr = curr->next; } return head; } ``` 🟦:這邊有個小問題,其實第二個 if 判斷,與迴圈的中止條件重疊,是不是其實不需要? 🟨:對,這行是不需要的。 🟦:接下來給你一個 follow-up,刪除重複的數字的時候,要把有重複的數字全部刪除。 🟨:我的思路是定義一個 boolean,標記 curr 節點是不是屬於重複的節點,以及一個 previous 節點。一旦比對下一個是一樣的,就把目前的 curr 節點標為 true,然後刪除的操作跟之前一樣,但是如果比對到下一個不一樣的話,要看標記是否為 true,若為 true,就要把這個 curr 節點刪掉,並把 prev 節點的指標指向 curr 的下一個。 ```c struct node *deleteDuplicate(struct node *head) { if (!head) return head; bool is_curr_dupli = false; struct node *curr = head, *prev = head; for (; curr->next != NULL;) { if (curr->val == curr->next->val) { is_curr_dupli = true; struct node *dupli = curr->next; curr->next = curr->next->next; free(dupli); if (is_curr_dupli && curr->next = NULL) { prev = curr->next; free(curr); is_curr_dupli = false; } } else { if (is_curr_dupli) { prev = curr->next; struct node *delete = curr; curr = curr->next; free(delete); is_curr_dupli = false; } else curr = curr->next; } } return head; } ``` ## [Leetcode 119.](https://leetcode.com/problems/pascals-triangle-ii/description/) 🟦 Interviewer : 伏爾泰 Voltaire 🟨 Interviewee : 周瑜 Zhou Yuuu --- ### 面試過程 🟦:您好,我們現在開始面試。請您設想您現在加入了一個開發即時分析工具的團隊。我們的任務是要在前端圖表顯示二項分佈的係數。您的工作是實作一個函式,用於計算這些二項分佈的係數。 🟦:該函式需要輸入一個整數 N,並回傳第 N 列的二項分佈係數。 🟨:有的。想請問 N 的起始值是0還是1呢? 🟦: N 的起始值是0。 🟨:所以如果輸入N = 0時,輸出應該為內容只有一個數字1的一維陣列對嗎。 🟦: 沒錯 🟨:那我再舉幾個例子確認我的想法無誤。 ``` n=2 [1,2,1] n=3 [1,3,3,1] ``` 🟦: 沒有問題,你可以開始撰寫程式了。 🟨:好的。那我先說明我初步的想法。我目前想到最直觀的方法是列出從 0 到 N 的所有列。由於每一列的元素是上一列相鄰兩個元素的總和,我可以使用一個二維陣列 來儲存所有的列。最後,再根據輸入的 N 值,回傳指定的那一列結果。 🟦:好的,聽起來邏輯沒有問題,就先從這裡開始嘗試吧。 #### Code 1 ```cpp= vector<int> getRow(int n) { vector<vector<int>> triangle; for(int i = 0; i < n + 1; i++){ vector<int> row(i + 1); row[0] = 1; row[i] = 1; triangle.push_back(row); } for(int i = 1; i < n; i++){ for(int j = 0; j < i; j++){ triangle[i + 1][j + 1] = triangle[i][j + 1] + triangle[i][j]; } } vector<int> output; for(int i = 0; i < n + 1; i++) output.push_back(triangle[n][i]); return output; } ``` 🟦:程式碼的邏輯看起來沒有問題。不過,我想進行一個延伸討論。您目前使用了二維陣列來儲存所有結果,以及一個 output 陣列來儲存最終結果。您是否有思考過優化空間複雜度,只使用一個大小為 N+1 的一維陣列來完成整個計算過程? 🟨:我確實有考慮過這一點。由於每一行只與其上一行相關,確實不需要儲存整個帕斯卡三角形。我們可以重複利用同一個大小為 N+1 的陣列。 🟨:在更新時,我認為必須從後面的數字往前更新 (倒序)。 🟦:請您進一步闡述為什麼必須從後方更新,以及如果從前面開始更新會導致覆蓋 (Overwrite) 問題的具體過程。 🟨:好的。如果我們從前向後更新,當我們計算當前列的某個數字時,它需要用到上一列中前方相鄰的數值。但若從前往後更新,前方的數值已經被當前列的計算結果所覆蓋。這樣一來,後續運算就會使用到被修改過的新值而不是上一列的舊值,導致結果錯誤。因此,我們必須從後往前更新,以確保每次使用的都是上一列未被覆蓋的值。 #### Code2 ```cpp= vector<int> getRow(int n) { vector<int> row(n + 1, 0); row[0] = 1; for(int i = 0; i < n; i++){ for(int j = i + 1; j > 0; j--){ row[j] = row[j] + row[j - 1]; } } return row; } ``` 🟨:用n=3的例子來說明一維矩陣的更新。 ``` n=0[1,0,0,0] n=1[1,1,0,0] n=2 [1,2,1,0] n=3 [1,3,3,1] ``` 🟨:這樣的優化能將空間複雜度從 O(N²) 降至 O(N),時間複雜度仍為 O(N²),因為仍需遍歷所有元素。 🟦:很好。您對更新順序的說明也很清楚。這樣的解法既節省記憶體,又維持正確性。今天的面試到此結束,謝謝。