LeetCode513. 找樹左下角的值

Tomorrowland_D發表於2024-07-25

題目連結: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. 我們遞迴函式要傳入的引數和遞迴函式的返回值
  2. 遞迴結束的條件(也就是遞迴的邊界)
  3. 單層遞迴的邏輯

其實本題當中遞迴裡面也蘊含著回溯的邏輯,其實所有的遞迴演算法都離不開回溯,只是我們沒有意識到回溯的過程,或者說回溯的過程被隱藏掉了。

下面的程式碼中我會重點強調回溯的邏輯

步驟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;
    }
};

相關文章