## LeetCode 模擬面試練習 >[video](https://youtu.be/0Yjj4ODsC60) ### [701. Insert into a Binary Search Tree](https://leetcode.com/problems/insert-into-a-binary-search-tree/?envType=list&envId=rswxsja3) Interviewer: 早上好,馬先生。感謝您今天的參與。在我們開始之前,請您簡單介紹一下您自己。 Interviewee: 早上好,我是馬邦德,畢業於成功大學資訊工程系,過去在鵝城擔任軟體工程師,專注於後端開發和資料結構的設計。 Interviewer: 太好了。目前公司正在為一個網購平台建立新的商品管理系統。 這個平台有數以萬計的商品,每個商品都有自己的價格和庫存資訊。由於平台非常受歡迎,每天都會有大量的價格更新和庫存變動。我們希望能夠迅速地找到和更新特定的商品資訊。 對於如何優化這個流程。你有什麼想法嗎? Interviewee: 如果我理解正確的話,我需要設計一個函式,這個函式接收一個新的商品並加入到系統的資料庫中,並能保持原先的結構和排序特性,對吧? Interviewer: 完全正確。 Interviewee: 那我想使用二元搜尋樹(BST)來儲存商品訊息,以商品的價格作為排序的依據。 而函式要能夠接收一個BST的根節點和一個商品,然後將該商品插入到BST中的正確位置,以保持樹的結構。 Interviewer: 聽起來不錯。 Interviewee: 例如,如果我們有一個二元搜尋樹,根節點是 5,並且我要插入一個值 3,那麼 3 應該會被插入到 5 的左子節點。 Interviewer: 了解。 Interviewee: 我的做法是遞迴。從根節點開始,如果新的值小於當前節點的值,我將向左遞迴;如果新的值大於當前節點的值,我將向右遞迴。當達到一個空節點時,我將在這裡插入新的節點。 ``` c // 定義二元搜尋樹的節點結構 struct TreeNode { int val; // 節點值 struct TreeNode *left; // 左子節點指針 struct TreeNode *right; // 右子節點指針 }; // 函式: 在二元搜尋樹中插入一個新節點 struct TreeNode* insertIntoBST(struct TreeNode* root, int val) { // 如果根節點是空的,創建一個新節點,並將其返回作為新的根節點 if (root == NULL) { struct TreeNode* new_node = malloc(sizeof(struct TreeNode)); new_node->val = val; new_node->left = NULL; new_node->right = NULL; return new_node; } // 如果要插入的值小於根節點的值,遞迴在左子樹中插入 if (val < root->val) { root->left = insertIntoBST(root->left, val); } // 如果要插入的值大於根節點的值,遞迴在右子樹中插入 else if (val > root->val) { root->right = insertIntoBST(root->right, val); } // 返回可能已經更新的根節點 return root; } ``` Interviewee: 讓我來測試一下代碼是否能順利運行 ``` c #include <stdio.h> #include <stdbool.h> #include <limits.h> #include<stdlib.h> // 定義二元樹節點結構 struct treenode { int val; struct treenode* left; struct treenode* right; }; //檢測一個樹是否是BST bool isBSTUtil(struct treenode* node, int min, int max) { if (node == NULL) { return true; // 空樹是BST } if (node->val <= min || node->val >= max) { return false; // 不滿足BST特性 } // 遞歸檢查左子樹和右子樹 return isBSTUtil(node->left, min, node->val) && isBSTUtil(node->right, node->val, max); } struct treenode* insertIntoBST(struct treenode* root, int val) { if (root == NULL) { struct treenode* new_node = malloc(sizeof(struct treenode)); new_node->val = val; new_node->left = NULL; new_node->right = NULL; return new_node; } if (val < root->val) { root->left = insertIntoBST(root->left, val); } else if (val > root->val) { root->right = insertIntoBST(root->right, val); } return root; } int main() { // 構建一個示例二元樹 struct treenode* root = malloc(sizeof(struct treenode)); root->val = 10; root->left = NULL; root->right = NULL; // 插入新節點 root = insertIntoBST(root, 5); root = insertIntoBST(root, 15); root = insertIntoBST(root, 2); root = insertIntoBST(root, 7); root = insertIntoBST(root, 7); // 檢測樹是否是BST if (isBSTUtil(root,INT_MIN, INT_MAX)) { printf("這棵樹是二元搜索樹。\n"); } else { printf("這棵樹不是二元搜索樹。\n"); } return 0; } ``` Interviewer: 你的解決方案很清楚。請問你的這個函式的時間和空間複雜度是什麼? Interviewee: 在遞迴版本中,時間複雜度是 O(h),其中 h 是樹的高度。每一個遞迴呼叫都會走訪樹的一個節點,直至找到適當的插入位置。而空間複雜度是主要由於遞迴呼叫堆疊的深度,它也是 O(h)。在平衡的情況下,h 是 log(n),所以時間和空間複雜度都是 O(log n);但是,在最壞的情況下,樹可能是非常偏斜的,使得 h 接近 n,因此時間和空間複雜度都是 O(n)。 Interviewer: 非常好。那如果我們想要優化這個函式以達到更好的效能,您會怎麼做? Interviewee: 我打算避免遞迴並使用迭代來找到新節點應該插入的位置, 在最壞的情況下(樹是完全不平衡的),時間複雜度是 O(n),其中 n 是樹中的節點數。在最好的情況下(樹是完全平衡的),時間複雜度是O(logn) 而空間複雜度由於避免了遞迴,減少到 O(1)。 這個方法也保留了二元搜尋樹的特性,並能夠正確地插入新節點。 Interviewer: 非常感謝您的回答和努力,馬先生。我們稍後會通知您面試的結果。祝您今天過得愉快! Interviewee: 謝謝您,期待您的回音。再見! --- ## 簡介你對其他同學的批評 (正反面都有),和你從中學到什麼 ## 1.塔塔 Jennifer (補充) > 10:08: 「有沒有其他解法解這個問題?」可以換個方式問,問說有沒有覺得這個解法哪裡可以換做其他解法去嘗試看看。 > 12:23 缺少了Test的部分,沒有去說服為什麼這麼寫會正確 缺少了Optimize的部分 ## 2.優嬉兔-UCI-他評 05 ### interviewer - [ ] 優點 * 口齒清晰 - [ ] 可改進的地方 * 建議不要直接使用leetcode原題,可對題目做適當的包裝 * 對話內容有點太制式 ### interviewee - [ ] 優點 * 在書寫程式碼的過程中有搭配適度的解釋 - [ ] 可改進的地方 * 缺少test的環節 ### 3.半條悟-satoru - 他評06 ### Interviewer - [ ] 優點 * 表達相當清楚 - [ ] 可改進之處 * 若能跟Interviewee有更多互動會更好 ### Interviewee - [ ] 優點 * REATO做的相當完整 * 在書寫程式碼的過程中有搭配很詳細的解釋 - [ ] 可改進之處 * 最後問Interviewer:「有任何問題嗎?」有點奇怪 ## 4. 梅治玄 - 他評03 ### interviewer 優點 - 對問題的描述清晰 - 在討論題目的過程中與interviewee互動良好 可改進處 - 可以用情境包裝題目避免直接使用leetcode原題(甚至是leetcode介面) ### interviewee 優點 - 對題目的提問很關鍵 可改進處 - [0:40](https://youtu.be/e26UBgzbv3A?t=40)把「整理一下思緒」改成「確認一下題目」會顯得較專業 其他建議 - 馬賽克有點跑掉 ## 5. 沐揚仁-sheep-他評 04 ### interviewer #### 優點 - 從一開始的互動到題目的設計都相當用心,非常自然 #### 可改進之處 - 優化的部分可以沿神多一點討論 ### interviewee #### 優點 - 對題目的提問很非常關鍵 - E的部分解釋很清楚,甚至有附上表格 - 有注意排版 - 在書寫程式碼的過程中對程式碼的解釋也相當清楚 #### 可改進之處 - 英文口說可以更自信一點