題目連結:https://leetcode.cn/problems/find-bottom-left-tree-value/description/
題目敘述:
給定一個二叉樹的 根節點 root,請找出該二叉樹的 最底層 最左邊 節點的值。
假設二叉樹中至少有一個節點。
示例 1:
輸入: root = [2,1,3]
輸出: 1
示例 2:
輸入: [1,2,3,4,null,5,6,null,null,7]
輸出: 7
提示:
二叉樹的節點個數的範圍是 [1,10^4]
-2^31 <= Node.val <= 2^31 - 1
思路:
這題我們有遞迴和迭代兩種寫法,我們在這裡重點介紹遞迴的解法,如果用層序遍歷的迭代法的話,我們這道題就十分簡單了,不過我在後面也會介紹層序遍歷的寫法。
遞迴法
遞迴法我們一定要清楚的是三點:
- 我們遞迴函式要傳入的引數和遞迴函式的返回值
- 遞迴結束的條件(也就是遞迴的邊界)
- 單層遞迴的邏輯
其實本題當中遞迴裡面也蘊含著回溯的邏輯,其實所有的遞迴演算法都離不開回溯,只是我們沒有意識到回溯的過程,或者說回溯的過程被隱藏掉了。
下面的程式碼中我會重點強調回溯的邏輯
步驟1.確定我們的引數和返回值
這題的引數,既然是要求最後一層的最左邊的節點,那麼我們必然要使用一個引數depth
來表示深度,然後我們也需要一個引數maxdepth
來表示當前是否是達到了最大的深度,不過這個maxdepth
變數不需要
傳入函式中,我們可以定義為全域性變數,如果depth>maxdepth,就證明當前還未到達最大深度,也就不是我們要處理的最左邊的節點了。 同時,我們還需要一個引數result
來接收我們需要求得這個節點的節點
值,這個變數我們也定義為全域性變數。
確定遞迴的中止條件
我們要處理的是什麼節點?是不是葉子節點,我們處理葉子節點的邏輯判斷是什麼?是不是隻需要當前這個節點它的左右孩子都為空的時候,我們就到達了我們需要處理的時候了,這個時候就是返回的時候了。
那我們要處理這個節點,要做些什麼事情呢?——我們要判斷當前深度是否是最大深度,如果不是,我們就得更新這個最大深度,同時我們要更新result變數的值,然後再返回,這樣就處理好了遞迴的邊界條件,
對吧?
這段邏輯的程式碼如下:
//處理到葉子節點就返回
if(cur->left==NULL&&cur->right==NULL){
if(depth>maxdepth){
maxdepth=depth;
result=cur->val;
}
return;
}
單層遞迴的邏輯
我們現在找到了最深層次的葉子節點,那麼我們如何保證它一定是最左邊的節點呢?那還不簡單嘛!只需要我們處理遞迴的時候,優先處理左子樹,不就能保證我們先處理的是左孩子了嘛!對吧,
這段邏輯的程式碼如下:
if(cur->left!=NULL){
//先讓depth++,讓他處理下一層的節點
depth++;
traversal(cur->left,depth);
//再讓depth--,這就是回溯的過程,退到上一層的節點,再處理右邊的子樹
depth--;
}
if(cur->right!=NULL){
//這裡也是一樣的道理
depth++;
traversal(cur->right,depth);
//這裡也是回溯的過程
depth--;
}
其實,處理好了這幾個邊界條件,我們的程式碼就出來了
整體程式碼:
class Solution {
public:
int result=0;
int maxdepth=INT_MIN;
void traversal(TreeNode*cur,int depth){
//處理到葉子節點就返回
if(cur->left==NULL&&cur->right==NULL){
if(depth>maxdepth){
maxdepth=depth;
result=cur->val;
}
return;
}
if(cur->left!=NULL){
//先讓depth++,讓他處理下一層的節點
depth++;
traversal(cur->left,depth);
//再讓depth--,這就是回溯的過程,退到上一層的節點,再處理右邊的子樹
depth--;
}
if(cur->right!=NULL){
//這裡也是一樣的道理
depth++;
traversal(cur->right,depth);
//這裡也是回溯的過程
depth--;
}
}
int findBottomLeftValue(TreeNode* root) {
traversal(root,0);
return result;
}
};
層序遍歷(迭代法)
其實,這題使用層序遍歷才是最方便,最簡單的做法。我們只需要處理每一層的第一個元素,然後處理到最後一層,它自然就是最後一層的左邊第一個元素了,這題只需要在層序遍歷的模板上面改動一點點
就可以實現了!
如果不會層序遍歷的話,推薦去看看我的層序遍歷的文章,裡面詳細講解了層序遍歷實現的過程!
層序遍歷:https://www.cnblogs.com/Tomorrowland/p/18318744
class Solution {
public:
int findBottomLeftValue(TreeNode* root) {
queue<TreeNode*> que;
if (root != NULL) que.push(root);
int result = 0;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (i == 0) result = node->val; // 記錄最後一行第一個元素
if (node->left) que.push(node->left);
if (node->right) que.push(node->right);
}
}
return result;
}
};