Binary Tree Right Side View (二元樹的右視圖) 🟡 Medium¶
📌 LeetCode #199 — 題目連結 | NeetCode 解說
1. 🧐 Problem Dissection (釐清問題)¶
題目給一個 Binary Tree,想像你站在這棵樹的 右側 往左看。 請回傳你從上到下能看到的節點值。
-
Input:
root = [1,2,3,null,5,null,4] -
Output:
[1,3,4] - Input:
root = [1,null,3] - Output:
[1,3] - Input:
[] - Output:
[] - Constraints:
- \(0 <= nodes <= 100\)
- \(-100 <= Node.val <= 100\)
2. 🐢 Brute Force Approach (暴力解)¶
這題本質就是 Level Order Traversal,但是每一層只取**最後一個**元素。
3. 💡 The "Aha!" Moment (優化)¶
Approach 1: BFS (Level Order) 同上一題。 每層遍歷最後一個元素 q.back() or 在 loop 內的 i == size-1 時取值。
- Time: \(O(n)\)。
- Space: \(O(n)\) (Queue width)。
Approach 2: DFS (Reverse Pre-order) 這是一種聰明的 DFS。 我們可以優先遍歷 右子樹 (Root -> Right -> Left)。 這樣對於每一層深度 depth,我們**第一次**到達該深度的節點,一定是右視圖能看到的節點。
vec存結果。dfs(node, depth):- 如果
depth == vec.size(),代表這是我們第一次來到這一層 ->vec.push_back(node->val) dfs(right, depth + 1)dfs(left, depth + 1)
- 如果
- Time: \(O(n)\)。
- Space: \(O(h)\) (Recursion stack)。如果樹很深,DFS 空間可能比 BFS 差 (Skewed Tree)。如果樹很寬,BFS 空間比 DFS 差。
面試時 BFS 更直觀,DFS 更優雅(代碼短)。
🎬 Visualization (演算法視覺化)¶
4. 💻 Implementation (程式碼)¶
Approach: Iterative BFS (Queue)¶
#include <vector>
#include <queue>
using namespace std;
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode() : val(0), left(nullptr), right(nullptr) {}
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (!root) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int size = q.size();
for (int i = 0; i < size; i++) {
TreeNode* node = q.front();
q.pop();
// Keep the last node of each level
if (i == size - 1) {
result.push_back(node->val);
}
if (node->left) q.push(node->left);
if (node->right) q.push(node->right);
}
}
return result;
}
};
Approach: Recursive DFS (Right-first)¶
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> res;
dfs(root, 0, res);
return res;
}
void dfs(TreeNode* node, int depth, vector<int>& res) {
if (!node) return;
// 如果當前深度 == output size,代表我們第一次到達這一層
// 由於我們是先遍歷右邊,這一定是這一層最右邊的節點
if (depth == res.size()) {
res.push_back(node->val);
}
dfs(node->right, depth + 1, res);
dfs(node->left, depth + 1, res);
}
};
Python Reference¶
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
res = []
q = collections.deque()
if root:
q.append(root)
while q:
rightSide = None
qLen = len(q)
for i in range(qLen):
node = q.popleft()
if node:
rightSide = node
q.append(node.left)
q.append(node.right)
if rightSide:
res.append(rightSide.val)
return res
5. 📝 Detailed Code Comments (詳細註解)¶
class Solution {
public:
vector<int> rightSideView(TreeNode* root) {
vector<int> result;
if (root == nullptr) return result;
queue<TreeNode*> q;
q.push(root);
while (!q.empty()) {
int levelSize = q.size();
// 遍歷這一層的所有節點
for (int i = 0; i < levelSize; i++) {
TreeNode* curr = q.front();
q.pop();
// 如果是這一層的最後一個節點,它就是右視圖看到的那個
if (i == levelSize - 1) {
result.push_back(curr->val);
}
// 繼續將下一層的節點加入 Queue
// 順序:先左後右
if (curr->left) q.push(curr->left);
if (curr->right) q.push(curr->right);
}
}
return result;
}
};
6. 📊 Rigorous Complexity Analysis (複雜度分析)¶
- Time Complexity: \(O(n)\)
- BFS 遍歷每個節點一次。
- Space Complexity: \(O(n)\)
- Queue 保存一層的節點。對於 Full Binary Tree,最後一層有 \(n/2\) 個節點。
7. 💼 Interview Tips (面試技巧)¶
🎯 Follow-up 問題¶
面試官可能會問的延伸問題:
- Left Side View?
- 多個方向?
🚩 常見錯誤 (Red Flags)¶
避免這些會讓面試官扣分的錯誤:
- ⚠️ BFS 取錯節點
- ⚠️ DFS 順序錯誤
✨ 加分項 (Bonus Points)¶
這些會讓你脫穎而出:
- 💎 BFS 取每層最後一個
- 💎 DFS 先右後左