「程式碼隨想錄演算法訓練營」第十三天 | 二叉樹 part3

云雀AC了一整天發表於2024-07-17

110. 平衡二叉樹

題目連結:https://leetcode.cn/problems/balanced-binary-tree/
題目難度:簡單
文章講解:https://programmercarl.com/0110.平衡二叉樹.html
影片講解:https://www.bilibili.com/video/BV1Ug411S7my
題目狀態:透過

思路:

採用遞迴的方式,遍歷每個節點的左右孩子的深度以及其之間的深度差是否超過 1,如果超過 1 的話,就直接返回false,直到遍歷結束。

程式碼實現:

/**
 * Definition for a binary tree node.
 * 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:
    int isBalancedUtil(TreeNode *root, int &balanced) {
        if(root == nullptr) return 0;
        int leftHeight = isBalancedUtil(root->left, balanced);
        if(balanced == 0) return 0;
        int rightHeight = isBalancedUtil(root->right, balanced);
        if(balanced == 0) return 0;
        if(abs(leftHeight - rightHeight) > 1) balanced = 0;
        return max(leftHeight, rightHeight) + 1;
    }
    bool isBalanced(TreeNode* root) {
        int balanced = 1;
        isBalancedUtil(root, balanced);
        return balanced;
    }
};

程式碼隨想錄提供了一種更好的程式碼:

class Solution {
public:
    int getHeight(TreeNode *node) {
        if(node == nullptr) return 0;
        int leftHeight = getHeight(node->left);
        if(leftHeight == -1) return -1;
        int rightHeight = getHeight(node->right);
        if(rightHeight == -1) return -1;
        return abs(leftHeight - rightHeight) > 1 ? -1 : (max(leftHeight, rightHeight) + 1);
    }
    bool isBalanced(TreeNode *root) {
        return getHeight(root) == -1 ? false : true;
    }
};

257. 二叉樹的所有路徑

題目連結:https://leetcode.cn/problems/binary-tree-paths/
題目難度:簡單
文章講解:https://programmercarl.com/0257.二叉樹的所有路徑.html
影片講解:https://www.bilibili.com/video/BV1ZG411G7Dh
題目狀態:一點思路也沒有

學習思路:

學習回溯,看下圖

回溯和遞迴是不分開的,當每次進行遞迴的時候將之前儲存的路徑中的節點pop出去,這就是回溯。

定義遞迴函式:

  1. 傳入引數:
    a. TreeNode *node:傳入一個節點。
    b. vector<int> path:透過一個path來記錄沿途的路徑,便於之後的回溯。
    c. vector<string> res:用來記錄最終結果。
  2. 返回值:沒有返回值,遞迴的結果在res中存放。
  3. 終止條件:當該節點的左孩子和右孩子都為nullptr時,遞迴終止。
  4. 遞迴思路:採用前序遍歷,先將節點壓入path中,再判斷其左右孩子是否都為nullptr(此時為遞迴結束,即該節點為葉子節點),若不為nullptr,分別將其左右孩子(不為空的那個)進入遞迴,此時將path中該節點pop出來(這個就是回溯)。

程式碼實現:

/**
 * Definition for a binary tree node.
 * 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:
    void backtracking(TreeNode *node, vector<int> &path, vector<string> &res) {
        // 中
        path.push_back(node->val);
        // 終止條件
        if(node->left == nullptr && node->right == nullptr) {
            string sPath;
            for(int i = 0; i < path.size() - 1; ++i) {
                sPath += to_string(path[i]);
                sPath += "->";
            }
            sPath += to_string(path[path.size() - 1]);
            res.push_back(sPath);
            return;
        }
        // 左
        if(node->left) {
            backtracking(node->left, path, res);
            path.pop_back();
        }
        // 右
        if(node->right) {
            backtracking(node->right, path, res);
            path.pop_back();
        }
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> res;
        vector<int> path;
        if(root == nullptr) return res;
        backtracking(root, path, res);
        return res;
    }
};

404. 左葉子之和

題目連結:https://leetcode.cn/problems/sum-of-left-leaves/
題目難度:簡單
文章講解:https://programmercarl.com/0404.左葉子之和.html
影片講解:https://www.bilibili.com/video/BV1GY4y1K7z8
題目狀態:透過

個人思路:

定義一個int型別變數leftSum,用來儲存結果使用層序遍歷,當遍歷到該節點的左孩子時,若其左孩子沒有左孩子和右孩子(即該節點的左孩子為葉子節點),將其值加入leftSum中。

程式碼實現:

/**
 * Definition for a binary tree node.
 * 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:
    int sumOfLeftLeaves(TreeNode* root) {
        queue<TreeNode *> que;
        if(root == nullptr) return 0;
        int leftSum = 0;
        que.push(root);
        while(!que.empty()) {
            TreeNode *node = que.front();
            que.pop();
            if(node->left) {
                que.push(node->left);
                if(node->left->left == nullptr && node->left->right == nullptr) leftSum += node->left->val;
            }
            if(node->right) que.push(node->right);
        }
        return leftSum;
    }
};

遞迴思想的程式碼:

/**
 * Definition for a binary tree node.
 * 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:
    int sumOfLeftLeaves(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 0;
        int leftValue = sumOfLeftLeaves(root->left);
        if(root->left && !root->left->left && !root->left->right) leftValue += root->left->val;
        int rightValue = sumOfLeftLeaves(root->right);
        // 這裡面leftValue代表左孩子的左葉子節點值之和,rightValue代表右孩子的左葉子節點值之和
        int sum = leftValue + rightValue;
        return sum;
    }
};

222. 完全二叉樹的節點個數

題目連結:https://leetcode.cn/problems/count-complete-tree-nodes/
題目難度:簡單
文章講解:https://programmercarl.com/0222.完全二叉樹的節點個數.html
影片講解:https://www.bilibili.com/video/BV1eW4y1B7pD
題目狀態:透過

思路:

層序遍歷,加個計數sum

程式碼實現:

/**
 * Definition for a binary tree node.
 * 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:
    int countNodes(TreeNode* root) {
        queue<TreeNode *> que;
        if(root == nullptr) return 0;
        que.push(root);
        int sum = 1;
        while(!que.empty()) {
            TreeNode *node = que.front();
            que.pop();
            if(node->left) {
                que.push(node->left);
                sum++;
            }
            if(node->right) {
                que.push(node->right);
                sum++;
            }
        }
        return sum;
    }
};

遞迴方法:(利用完全二叉樹的特性,2的深度次方-1,這樣只需要遍歷完全二叉樹的左孩子和右孩子最邊上的節點即可)

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) return 0;
        TreeNode* left = root->left;
        TreeNode* right = root->right;
        int leftDepth = 0, rightDepth = 0; // 這裡初始為0是有目的的,為了下面求指數方便
        while (left) {  // 求左子樹深度
            left = left->left;
            leftDepth++;
        }
        while (right) { // 求右子樹深度
            right = right->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // 注意(2<<1) 相當於2^2,所以leftDepth初始為0
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};

相關文章