1. 程式人生 > 其它 >程式碼隨想錄:二叉樹的屬性

程式碼隨想錄:二叉樹的屬性

二叉樹的深度

遞迴法獲得二叉樹的深度

樹的深度 -> 後序遍歷求根節點的高度 

思路:遞迴三步驟。求根節點的高度,即最大深度,可以用後序遍歷的邏輯

1.確定函式形式,返回型別,引數:輸入一個TreeNode,返回一個int深度,so

int getMaxDepth(treeNode * node)

2. 確定終止條件: 如果node為空,就返回0,表示高度為0

if(node == NULL) return 0;

3. 確定遞迴邏輯:對一個節點而言,看左右子節點返回的高度,哪個高度大作為該節點的返回(+1是加了當前節點的高度1)

int leftDepth = getMaxDepth(node->left);
int rightDepth = getMaxDepth(node->right);
int maxDepth = 1 + max(leftDepth, rightDepth);
return maxDepth;

  

整合程式碼

class Solution {
public:
    int getdepth(TreeNode* root) {
        if (root == NULL) return 0;
        int leftdepth = getdepth(root->left);       //
        int rightdepth = getdepth(root->right);     //
        int depth = 1 + max(leftdepth, rightdepth); //
        return depth;
    }
    
int maxDepth(TreeNode* root) { return getdepth(root); } };

還可以精簡程式碼:

class solution {
public:
    int maxdepth(treenode* root) {
        if (root == null) return 0;
        return 1 + max(maxdepth(root->left), maxdepth(root->right));
    }
};

 

前序遍歷求深度

實際上前序遍歷才能體現求深度的真正邏輯

class Solution {
public:
    int result;
    void getdepth(TreeNode* root, int depth){
        //前序遍歷 中 左 右
        result = depth > result?depth : result;//中
        if(root->left==NULL &&root->right==NULL) return;
        if(root->left){//左
            depth++;
            getdepth(root->left,depth);
            depth--;//回溯
        }
        if(root->right){//右
            depth++;
            getdepth(root->right,depth);
            depth--;//回溯
        }
        return;
    }

    int maxDepth(TreeNode* root) {
        result = 0;
        if(root==NULL) return result;
        getdepth(root,1);
        return result;
    }
}

  

上面有步驟可以簡化程式碼

if(root->left) getDepth(node->left, depth + 1);
if(root->right) getDepth(node->right, depth + 1);

  

迭代法獲得二叉樹的深度

 可以用層序遍歷法來得到二叉樹的最大深度和最小深度

二叉樹的最大深度

104. 二叉樹的最大深度 - 力扣(LeetCode) (leetcode-cn.com)

給定一個二叉樹,找出其最大深度。

二叉樹的深度為根節點到最遠葉子節點的最長路徑上的節點數。

說明: 葉子節點是指沒有子節點的節點

思路:層序遍歷,當每遍歷一層,就把深度加1,當遍歷完最後一層,佇列為空,退出。

/**
 * 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 maxDepth(TreeNode* root) {
        queue<TreeNode*> queueNode;
        if(root != NULL) queueNode.push(root);
        //空二叉樹拳頭警告
        //vector<vector<int>> res;
        int depth = 0;
        while(!queueNode.empty()){
            //每次遍歷一層,一層的節點在進入while時候確定,後面會改變,所以for迴圈中不能用size(),而應該用固定長度
            int layerSize = queueNode.size();
            for(int i =0;i<layerSize;i++){
                TreeNode *tempNode = queueNode.front();
                queueNode.pop();
                if(tempNode->left) queueNode.push(tempNode->left);
                if(tempNode->right) queueNode.push(tempNode->right);
            }
            depth+=1;
        }
        return depth;  
    }
};

 

二叉樹的最小深度

111. 二叉樹的最小深度 - 力扣(LeetCode) (leetcode-cn.com)

給定一個二叉樹,找出其最小深度。

最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。

錯的思路:當某層節點數不為2^(k-1)時,就可能為最小深度

 

注意,只有當左右孩子都為空的時候,才說明遍歷的最低點了。如果其中一個孩子為空則不是最低點

所以只有當某個節點左右孩子都指向NULL,才作為最小深度的層的節點

/**
 * 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 minDepth(TreeNode* root) {
        queue<TreeNode*> queueNode;
        if(root != NULL) queueNode.push(root);
        if(root == NULL) return 0;
        //空二叉樹拳頭警告
        //vector<vector<int>> res;
        int minDepth = 1;
        while(!queueNode.empty()){
            //每次遍歷一層,一層的節點在進入while時候確定,後面會改變,所以for迴圈中不能用size(),而應該用固定長度
            int layerSize = queueNode.size();
            
            for(int i =0;i<layerSize;i++){
                TreeNode *tempNode = queueNode.front();
                queueNode.pop();
                if(tempNode->left) queueNode.push(tempNode->left);
                if(tempNode->right) queueNode.push(tempNode->right);
                if(!tempNode->left && !tempNode->right) return minDepth;
            }
            minDepth+=1;
        }
        return minDepth;  
    }
};

 

 

平衡二叉樹

 

對稱二叉樹

101. 對稱二叉樹 - 力扣(LeetCode) (leetcode-cn.com)

也叫映象二叉樹,即判斷給定root的二叉樹是不是映象/對稱的。

對稱的二叉樹:

 

不對稱的二叉樹:

 

 

遞迴判斷對稱二叉樹

思路:遞迴。

關於中間對稱軸對稱的兩節點是否相同,而不僅僅是左右節點相同。so比較對稱的兩棵子樹是否是相互翻轉的。。

一個遞迴 左右中,一個遞迴 右左中,來比較對稱的子樹(左邊看和右邊看過去是一樣的)

 

 

既然是遞迴方法,遞迴三部曲:背(確定函式引數和返回值,確定終止條件,確定遞迴邏輯)

確定函式引數和返回值

這裡,要遞迴比較兩棵對稱的子樹是否是相互翻轉,引數為兩棵子樹的root,返回值是true 或者false.

bool cmp(TreeNode * left, TreeNode * right){
    //遞迴函式
}

確定終止條件

什麼時候不對稱呢返回false?外側空節點不對稱,內測空節點不對稱,當前root的val不相等

什麼時候對稱呢返回true?左右節點都不為空,且數值相同的情況(p.s. 另外還有一種情況,左右子樹都為空,即到了葉子節點)

if(left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left->val != right->val) return false;
else if (left == NULL && right == NULL) return true;

確定遞迴邏輯

處理左右子樹都不為空,且數值相同的情況。

要遞迴比較左子樹的外側和右子樹的外側 left->left vs right->right

要遞迴比較左子樹的內測和右子樹的內測 left->right vs right->left

只有當以上兩個比較都返回true時候,才返回true

bool outside = cmp(left->left, right->right);
bool inside = cmp(left->right, right->left);
return ouside&&inside;

  

完成程式碼:

/**
 * 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:
    bool cmp(TreeNode * left, TreeNode * right){
    //遞迴函式
    if(left == NULL && right != NULL) return false;
    else if (left != NULL && right == NULL) return false;
    else if (left == NULL && right == NULL) return true;
    else if (left->val != right->val) return false;//這一條要放到下面,不然可能會出現子節點為空就讀取val的錯誤

    //左右對稱節點不空,val相等的情況
    bool outside = cmp(left->left, right->right);
    bool inside = cmp(left->right, right->left);
    return outside && inside;
    }

    bool isSymmetric(TreeNode* root) {
        if(root==NULL) return true;
        return cmp(root->left, root->right);
    }
};

 

“迭代邏輯”判斷對稱二叉樹

使用佇列來遍歷二叉樹,把對應的元素按特定的順序放入佇列。每次比較兩個節點,看看相對應的節點是否相等

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(root==NULL) return true;
        //佇列存放比較節點
        queue<TreeNode*> que;
        que.push(root->left);
        que.push(root->right);
        while(!que.empty()){
            //把要比較的節點彈出來暫存 佇列先進先出
            TreeNode * leftTemp = que.front();
            que.pop();
            TreeNode * rightTemp = que.front();
            que.pop();
            //當相對的兩個節點都為空,則區域性對稱
            if(!leftTemp && !rightTemp) continue;
            //相對的兩個節點一空一有值,或者是都不為空但是值不相等
            if(leftTemp&&!rightTemp || !leftTemp&&rightTemp || (leftTemp->val!=rightTemp->val)) return false;

            //因為上面兩個if排除了為有空節點的情況,只剩下兩個節點不為空,且值相等,所以push沒毛病
            que.push(leftTemp->left);
            que.push(rightTemp->right);
            que.push(leftTemp->right);
            que.push(rightTemp->left);
        }
        return true;
    }
};

上面程式碼其實是把左右兩個子樹要比較的元素順序放進一個容器,然後成對成對的取出來進行比較。那麼除了佇列,使用棧也可以啊,只要把容器替換一下,佇列改為棧(因為成對成對彈出壓入,不用改什麼順序)。

平衡二叉樹

110. 平衡二叉樹 - 力扣(LeetCode) (leetcode-cn.com)

給定一個二叉樹,判斷它是否是高度平衡的二叉樹。本題中,一棵高度平衡二叉樹定義為:

一個二叉樹每個節點 的左右兩個子樹的高度差的絕對值不超過 1 。

思路:重點是平衡怎麼判斷?左右子樹的高度差絕對值小於等於1,既然是比較高度,遞迴+後序遍歷就可以了:

遞迴函式的引數和返回值:返回的是當前節點的高度,引數為當前節點的指標

int getHeight(TreeNode * root){
      //遞迴函式  
}

終止條件:如果遇到空節點(葉子節點指向的NULL),即返回 0

if(root == NULL) return 0;

單層遞迴邏輯: 先遞迴讀取左子樹高度,再遞迴讀取右子樹高度,相比較返回大的,並且差值如果大於等於2就不是平衡二叉樹(但是因為是遞迴演算法,不是很好直接退出函式返回,使用一個flag:-1 如果某一次的高度差大於1,那就是不平衡,一直影響到最後的輸出)

int leftHeight = getHeight(root->left);
if(leftHeight==-1) return -1;

int rightHeight = getHeight(root->right);
if(rightHeight==-1) return -1;

return abs(leftHeight - rightHeight) > 1? -1 :max(leftHeight, rightHeight)+1;

  

寫出程式碼:

/**
 * 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 getHeight(TreeNode* root){
        if(root == NULL) return 0;

        int leftHeight = getHeight(root->left);
        if(leftHeight==-1) return -1;
        int rightHeight = getHeight(root->right);
        if(rightHeight==-1) return -1;
        return abs(rightHeight-leftHeight) > 1? -1:max(rightHeight,leftHeight)+1;
    }
    bool isBalanced(TreeNode* root) {
        int heigh = getHeight(root);
        if(heigh==-1) return false;
        else return true;
    }
};