## 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的部分解釋很清楚,甚至有附上表格
- 有注意排版
- 在書寫程式碼的過程中對程式碼的解釋也相當清楚
#### 可改進之處
- 英文口說可以更自信一點