Leetcode 二叉樹解題報(bào)告

1. Binary Tree Preorder Traversal

Description

Given a binary tree, return the preorder traversal of its nodes' values.
Example:

Input: [1,null,2,3]
1

2
/
3

Output: [1,2,3]

Analysis

  1. 實(shí)際就是二叉樹的先序遍歷,先序?qū)?yīng)得是根節(jié)點(diǎn)的訪問順序。
  2. leetcode上樹節(jié)點(diǎn)的定義如下
struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right;
      TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 };
  1. 利用棧的思想,壓入根節(jié)點(diǎn),訪問值,退棧,壓入左右子節(jié)點(diǎn),訪問棧頂,退棧頂。直到棧為空。

Solution

// 使用棧記錄訪問過程中得節(jié)點(diǎn)指針,首先壓棧根節(jié)點(diǎn),訪問該節(jié)點(diǎn)數(shù)據(jù),后退棧,再將其右左節(jié)點(diǎn)壓棧。
// 不斷訪問棧頂后后退棧頂,直到棧為空。
class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode *> s;
        if(root!=nullptr)
            s.push(root);
        while(!s.empty())
        {
            TreeNode* p = s.top();
            result.push_back(p->val);
            s.pop();
            if(p->right!=nullptr)
                s.push(p->right);
            if(p->left!=nullptr)
                s.push(p->left);
        }
        return result;
    }
};


2.Binary Tree Inorder Traversal

Description

Given a binary tree, return the inorder traversal of its nodes' values.

Example:

Input: [1,null,2,3]
1

2
/
3

Output: [1,3,2]

Analysis

  1. 實(shí)際就是二叉樹的中序遍歷
  2. 不斷的壓入根左左左左,直到?jīng)]有左節(jié)點(diǎn)(即找到最左邊的節(jié)點(diǎn))。

Solution

// 從根節(jié)點(diǎn)開始不斷壓入根左左左左,直到?jīng)]有左節(jié)點(diǎn),訪問。
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode *> s;
        TreeNode* p = root;
        while(!s.empty() || p!=nullptr)
        {
            if(p!=nullptr)
            {
                s.push(p);
                p = p->left;
            }
            else
            {
                // 最左邊的節(jié)點(diǎn)
                p = s.top();
                s.pop();
                result.push_back(p->val);
                // 最關(guān)鍵
                p = p->right;
            }
        }
        return result;
        
    }
};

3.Binary Tree Postorder Traversal

Description

Given a binary tree, return the postorder traversal of its nodes' values.

Example:

Input: [1,null,2,3]
1

2
/
3

Output: [3,2,1]

Analysis

  1. 二叉樹后序遍歷
  2. 此題有難度,需要考慮右子樹的存在

Solution

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        vector<int> result;
        stack<TreeNode*> s;
        TreeNode *p=root, *q = nullptr;
        do
        {
            // 不斷往左下走
            while(p!=nullptr)
            {
                s.push(p);
                p = p->left;
            }
            q = nullptr;
            while(!s.empty())
            {
                p = s.top();
                s.pop();
                // 如果此時(shí)這個(gè)棧頂節(jié)點(diǎn)不存在右節(jié)點(diǎn),或者已經(jīng)被訪問,則訪問他
                if(p->right == q)
                {
                    result.push_back(p->val);
                    // 保存剛剛訪問的節(jié)點(diǎn)
                    q = p;
                }
                // 否則的話,該節(jié)點(diǎn)還不能訪問,重新進(jìn)站,先訪問其右子樹
                else
                {
                    s.push(p);
                    p = p->right;
                    break;
                }
            }
        }while(!s.empty());
        return result;
    }
};

總結(jié)

  1. 二叉樹的三種遍歷方式是二叉樹算法的前提。
  2. 二叉樹三種遍歷方法最簡(jiǎn)單的是用遞歸地方式,如下
// 先序
void preorder(TreeNode *root)
{
    if(root!=nullptr)
    {
        visit(root);
        preorder(root->left);
        preorder(root->right);
    }
}

// 中序
void inorder(TreeNode *root)
{
    if(root!=nullptr)
    {
        inorder(root->left);
        visit(root);
        inorder(root->right);
    }
}

// 后序
void postorder(TreeNode *root)
{
    if(root!=nullptr)
    {
        postorder(root->left);
        postorder(root->right);
        visit(root);
    }
}

  1. 遞歸方式很簡(jiǎn)單,所以要學(xué)會(huì)使用?;蚓€索二叉樹寫這三種遍歷。


4. Binary Tree Level Order Traversal

Description

Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level).

For example:
Given binary tree [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
return its level order traversal as:
[
[3],
[9,20],
[15,7]
]

Analysis

  1. 二叉樹的層序遍歷,層序遍歷是二叉樹的廣度優(yōu)先搜索方式,先后中遍歷都是二叉樹的深度優(yōu)先搜索方式。
  2. 建立一個(gè)queue,然后先把根節(jié)點(diǎn)放進(jìn)去,這時(shí)候找根節(jié)點(diǎn)的左右兩個(gè)子節(jié)點(diǎn),這時(shí)候去掉根節(jié)點(diǎn),此時(shí)queue里的元素就是下一層的所有節(jié)點(diǎn),用一個(gè)for循環(huán)遍歷它們,然后存到一個(gè)一維向量里,遍歷完之后再把這個(gè)一維向量存到二維向量里,以此類推,可以完成層序遍歷。
  3. 比較復(fù)雜的是需要將每層數(shù)分開
class Solution {
public:
    vector<vector<int> > levelOrder(TreeNode *root) {
        vector<vector<int> > res;
        if (root == NULL) return res;
        // 建立隊(duì)列
        queue<TreeNode*> q;
        // 根節(jié)點(diǎn)先入隊(duì)
        q.push(root);
        while (!q.empty()) {
            // 當(dāng)前層值得容器
            vector<int> oneLevel;
            int size = q.size();
            for (int i = 0; i < size; ++i) {
                TreeNode *node = q.front();
                q.pop();
                oneLevel.push_back(node->val);
                if (node->left) q.push(node->left);
                if (node->right) q.push(node->right);
            }
            res.push_back(oneLevel);
        }
        return res;
    }
};


5. Same Tree

Description

Given two binary trees, write a function to check if they are the same or not.

Two binary trees are considered the same if they are structurally identical and the nodes have the same value.

Analysis

  1. 判斷兩個(gè)二叉樹是否相同,必須樹結(jié)構(gòu)和相應(yīng)得節(jié)點(diǎn)值都相同。
  2. 樹結(jié)構(gòu)相同,就是比較是否一個(gè)這個(gè)地方有節(jié)點(diǎn),一個(gè)這個(gè)地方無節(jié)點(diǎn)。
  3. 采用遞歸得想法,分成三種情況: 如果兩個(gè)位置都是空,則是相同,如果一個(gè)空一個(gè)非空,則不同,最后根節(jié)點(diǎn),左子樹,右子樹三方判斷合并。

Solution

class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        // 如果兩個(gè)樹都是空,則是相同
        if(!p && !q)
            return true;
        // 如果一個(gè)空一個(gè)非空
        if(!p || !q)
            return false;
        // 根節(jié)點(diǎn),左子樹,右子樹三方判斷合并
        return (p->val==q->val) && (isSameTree(p->left, q->left)) 
        && (isSameTree(p->right, q->right));
    }
};


6. Symmetric Tree

Decription

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center).

Analysis

  1. 判斷一棵樹是否是對(duì)稱的。思路和判斷兩棵樹是否是相同的很類似。都是遞歸的思想,區(qū)別是,這里因?yàn)槭且豢脴洌孕枰瓤紤]根節(jié)點(diǎn)。后面三方合并的地方,判斷兩棵樹相同是同時(shí)遞歸做作,右右。判斷一棵樹是否對(duì)稱,應(yīng)該遞歸左右,右左。

Solution

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if(!root)
            return true;
        else
            return isSymmetric(root->left, root->right);
    }
    
    bool isSymmetric(TreeNode *p, TreeNode *q)
    {
        if(!p && !q)
            return true;
        if(!p || !q)
            return false;
        return (p->val == q->val) && (isSymmetric(p->left, q->right)) 
        && (isSymmetric(p->right, q->left));
    }
};


7. Construct Binary Tree from Preorder and Inorder Traversal

Description

Given preorder and inorder traversal of a tree, construct the binary tree.

Analysis

  1. 根據(jù)先序遍歷和中序遍歷結(jié)果,建立二叉樹
  2. 先序的順序的第一個(gè)肯定是根,所以原二叉樹的根節(jié)點(diǎn)可以知道,題目中給了一個(gè)很關(guān)鍵的條件就是樹中沒有相同元素,有了這個(gè)條件我們就可以在中序遍歷中也定位出根節(jié)點(diǎn)的位置,并以根節(jié)點(diǎn)的位置將中序遍歷拆分為左右兩個(gè)部分,分別對(duì)其遞歸調(diào)用原函數(shù)。

Solution

class Solution {
public:
    TreeNode *buildTree(vector<int> &preorder, vector<int> &inorder) {
        return buildTree(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }
    TreeNode *buildTree(vector<int> &preorder, int pLeft, int pRight, vector<int> &inorder, int iLeft, int iRight) {
        if (pLeft > pRight || iLeft > iRight) return NULL;
        int i = 0;
        for (i = iLeft; i <= iRight; ++i) {
            if (preorder[pLeft] == inorder[i]) break;
        }
        TreeNode *cur = new TreeNode(preorder[pLeft]);
        cur->left = buildTree(preorder, pLeft + 1, pLeft + i - iLeft, inorder, iLeft, i - 1);
        cur->right = buildTree(preorder, pLeft + i - iLeft + 1, pRight, inorder, i + 1, iRight);
        return cur;
    }
};

8. Construct Binary Tree from Inorder and Postorder Traversal

Description

Given inorder and postorder traversal of a tree, construct the binary tree.

Analysis

  1. 利用中序和后序遍歷,建立二叉樹
  2. 中序的遍歷順序是左-根-右,后序的順序是左-右-根,對(duì)于這種樹的重建一般都是采用遞歸來做。由于后序的順序的最后一個(gè)肯定是根,所以原二叉樹的根節(jié)點(diǎn)可以知道,題目中給了一個(gè)很關(guān)鍵的條件就是樹中沒有相同元素,有了這個(gè)條件我們就可以在中序遍歷中也定位出根節(jié)點(diǎn)的位置,并以根節(jié)點(diǎn)的位置將中序遍歷拆分為左右兩個(gè)部分,分別對(duì)其遞歸調(diào)用原函數(shù)。

Solution

class Solution {
public:
    TreeNode *buildTree(vector<int> &inorder, vector<int> &postorder) {
        return buildTree(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
    }
    TreeNode *buildTree(vector<int> &inorder, int iLeft, int iRight, vector<int> &postorder, int pLeft, int pRight) {
        if (iLeft > iRight || pLeft > pRight) return NULL;
        TreeNode *cur = new TreeNode(postorder[pRight]);
        int i = 0;
        for (i = iLeft; i < inorder.size(); ++i) {
            if (inorder[i] == cur->val) break;
        }
        cur->left = buildTree(inorder, iLeft, i - 1, postorder, pLeft, pLeft + i - iLeft - 1);
        cur->right = buildTree(inorder, i + 1, iRight, postorder, pLeft + i - iLeft, pRight - 1);
        return cur;
    }
};

總結(jié)

  1. 二叉樹是一種遞歸的數(shù)據(jù)結(jié)構(gòu),基本所有題目都可以考慮遞歸的思想。
  2. 遞歸一定是DFS,二叉樹的先序中序后序都可以看成是DFS。
  3. 遞歸和迭代的區(qū)別
  • 遞歸是重復(fù)調(diào)用函數(shù)自身實(shí)現(xiàn)循環(huán)。迭代是函數(shù)內(nèi)某段代碼實(shí)現(xiàn)循環(huán)
  • 遞歸循環(huán)中,遇到滿足終止條件的情況時(shí)逐層返回來結(jié)束。迭代則使用計(jì)數(shù)器結(jié)束循環(huán)。
  • 遞歸就是在過程或函數(shù)里面調(diào)用自身;在使用遞歸時(shí),必須有一個(gè)明確的遞歸結(jié)束條件,稱為遞歸出口.
  • 迭代是逐漸逼近,用新值覆蓋舊值,直到滿足條件后結(jié)束,不保存中間值,空間利用率高。遞歸是將一個(gè)問題分解為若干相對(duì)小一點(diǎn)的問題,遇到遞歸出口再原路返回,因此必須保存相關(guān)的中間值,這些中間值壓入棧保存,問題規(guī)模較大時(shí)會(huì)占用大量?jī)?nèi)存。


9. Minimum Depth of Binary Tree

Description

Given a binary tree, find its minimum depth.

The minimum depth is the number of nodes along the shortest path from the root node down to the nearest leaf node.

Note: A leaf is a node with no children.

Analysis

  1. 判斷一棵樹的最小深度,即最快找到葉子節(jié)點(diǎn)的深度。

遞歸,若為空樹返回0;

若左子樹為空,則返回右子樹的最小深度+1;(加1是因?yàn)橐由细@一層,下同)

若右子樹為空,則返回左子樹的最小深度+1;

若左右子樹均不為空,則取左、右子樹最小深度的較小值,+1;

Solution

class Solution {
public:
    int minDepth(TreeNode* root) {
        // 直接遞歸,初始根節(jié)點(diǎn)是沒有brother
        return minDepth(root, false);
    }
    
    int minDepth(TreeNode* p, bool hasbrother)
    {
        // 當(dāng)前節(jié)點(diǎn)是空節(jié)點(diǎn)
        if(!p)
            return hasbrother?INT_MAX:0;
        // 遞歸
        // 分別考慮左右子樹
        return 1+min(minDepth(p->left, p->right!=NULL), 
                    minDepth(p->right, p->left!=NULL));
        
    }
};


10. Maximum Depth of Binary Tree

Description

Given a binary tree, find its maximum depth.

The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node.

Note: A leaf is a node with no children.

Analysis

  1. 不需要考慮其它,直接遞歸

Solution

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if(!root)
            return 0;
        else
            return 1+max(maxDepth(root->left), maxDepth(root->right));
        
    }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容