1. 程式人生 > >Leetcode分類解析(二叉樹)

Leetcode分類解析(二叉樹)

持續更新中…

1.二叉樹中序遍歷

94.Binary Tree Inorder Traversal 二叉樹中序遍歷
98.Validate Binary Search Tree 驗證二叉搜尋樹
1.指定一個最小值LONG_MIN; 2.中序遍歷過程中如果出現降序,返回false; 3.過程中沒有返回false,最後返回true。

bool isValidBST(TreeNode* root) {
    long res=LONG_MIN;//這裡要注意是long型別的,
    while(p || !S.empty())//中序遍歷
    {
        ...
        if
(p->val <= res) return false; else res=p->val; ... } return true; }

99. Recover Binary Search Tree 恢復二叉搜尋樹
1.中序遍歷找到被交換的兩個節點的指標(0,2,4);2.交換相應節點的值。

void recoverTree(TreeNode* root);//恢復二叉搜尋樹
vector<TreeNode*> Inorder(TreeNode* root){//中序遍歷
vector<TreeNode*> v;//存放被交換的節點值 TreeNode* p=root, *tmp=NULL while(!s.empty() || p) { ... if(!tmp)//很重要 tmp=p; else { if(tmp->val > p->val) { v.push_back(tmp); v.push_back(p); } tmp=p; } ... } }

2.層遍歷

102 Binary Tree Level Order Traversal 二叉樹的層次遍歷
100.Same Tree 相同的樹
1.遞迴:前序遞迴到底,if(!p || !q) return p==q;否則p->val == q->val,左右遞迴

bool isSameTree(TreeNode* p, TreeNode* q) {
if(!p || !q)
    return p==q;//同為空才是true
return (p->val == q->val && isSameTree(p->left, q->left) && isSameTree(p->right, q->right));

2.非遞迴:用queue,
1.兩個樹層遍歷過程中,如果值不相等返回false;2.左兒子均不為空則入隊;3.左兒子一個空一個不空則返回false;4.右兒子同理;5.不滿足while出迴圈,如果兩個佇列均為空返回true,否則返回false。

while(!Q1.empty() && !Q2.empty())
{  
   ...
   if(p1->val!=p2->val)//1.
       return false;
   if(p1->left && p2->left)//2.
       入隊;
   else if(!(!p1->left && !p2->left))//3.
        return false;           
    4.右兒子同理 
   }  
if(Q1.empty() && Q2.empty()) //5.
    return true;  
return false;

101.Symmetric Tree 對稱二叉樹
遞迴:1.因為要判斷同一層上的,所以需要->left和->right同步!!!2.遞迴先序遍歷,1.if(!l && !r) return true; 2.if(!l || !r)return false; 3.if (l->val != r->val) return false;

bool isSymmetric(TreeNode* l,TreeNode* r) {
   if(!l && !r)
       return true;
   if(!l || !r)
       return false;
//注意:if (l->val == r->val) return true;是不對的,因為不能有一層是true就返回true,遞迴層
   if (l->val != r->val) 
       return false;
   return isSymmetric(l->left,r->right) && isSymmetric(l->right, r->left);    
}
bool isSymmetric(TreeNode* root) {
    if(!root)
        return true;
    return isSymmetric(root->left, root->right);
}

2.非遞迴:因為要判斷同一層上的,所以需要->left和->right同步,所以就需要兩個隊列了!!!並且在入佇列的時候,NULL也入,Q1從左到右,而Q2從右到左!!!(判斷兩個樹相同NULL節點不用入隊,只要兒子NULL不一樣就返回false;而對於對稱性,左->中間節點可能存在NULL,NULL也入隊,不用管兒子。)

while(!Q1.empty() && !Q2.empty())
{
    ...
    if(!p1 && !p2)//1.均為NULL
        continue;
    if(!p1 || !p2)//2.一NULL一非NULL
        return false;
    if(p1->val!=p2->val)//3.
        return false;
    Q1.push(p1->left);//4.先左後右,NULL也入隊
    Q1.push(p1->right);
    Q2.push(p2->right);//5.先右後左,NULL也入隊
    Q2.push(p2->left);
}
if(Q1.empty() && Q2.empty())
    return true;
else
    return false;

103.Binary Tree Zigzag Level Order Traversal 二叉樹的迴環層次遍歷
1.flag標誌確定本層是從左到右還是從右到左,本層結束取反即可;
2.v提前初始化為count個0,本層遍歷過程中v[i]=即可

bool flag=true;
while(!Q.empty())
{
    vector<int> vi(count,0);//count
    for(int i=0;i<count;++i)
    {
        ...
        int index = flag ? i : count-i-1;
        vi[index]=p->val;
        ...
   }
   flag=!flag;
}

107.Binary Tree Level Order Traversal II 值自底向上的層次遍歷
1.先求深度;2.層遍歷最後一層插入第一層的值即可,然後迴圈

int depth(TreeNode *root){//後序遍歷
    if (!root) 
        return 0;
    return max(depth(root->left),depth(root->right))+1;
}
int d= depth(root);
vector<vector<int> > v(d,vector<int>{});
while(!Q.empty())
{
    while(count)
    {
        ...
        v[d-1].push_back(p->val);//最後一層插入第一層的值即可
        ...
        --count;  
    }
    --d;
}

116.Populating Next Right Pointers in Each Node 每個節點的右向指標

while(!Q.empty())
{
    while(count)
    {
        ...
        if(count==1)//count為1,next指標為NULL;
            p->next=NULL;
        else
            p->next=q.front();
        ...
        --count;  
    }
}

199.Binary Tree Right Side View 二叉樹的右檢視
列印每層最右邊的節點的值即可

while(!Q.empty())
{
    while(count)
    {
        ...
        if(count == n)
            v.push_back(p->val);
        ...
        --count;  
    }
}

515. Find Largest Value in Each Tree Row 在每個樹行中找最大值
層遍歷即可
637. Average of Levels in Binary Tree 二叉樹的層平均值
層遍歷即可

3.like前序遍歷(去的過程中做事,回來返回每一層結果值)和like後序遍歷(去的過程中不做事,回來的過程中做事並返回值)

144.Binary Tree Preorder Traversal 二叉樹的前序遍歷
145.Binary Tree Postorder Traversal 二叉樹的後序遍歷
104.Maximum Depth of Binary Tree 二叉樹的最大深度

int depth(TreeNode *root){//後序遍歷
    if (!root) 
        return 0;
    return max(depth(root->left),depth(root->right))+1;
}

111.Minimum Depth of Binary Tree 二叉樹的最小深度

int minDepth(TreeNode* root) {//後序遍歷
    if(!root)
        return 0;
    int L=minDepth(root->left);
    int R=minDepth(root->right);
    //最小高度不是0,就選 min(L,R),否則選最大max(L,R)
    return (min(L,R) ? min(L,R) : max(L,R)) + 1;
}

110. Balanced Binary Tree 平衡二叉樹
1.開新函式,傳遞depth;2.後序遍歷計算每一層的高度差值depth。

bool isBalanced(TreeNode* root) {
    if(!root)
        return true;
    int depth=0;
    return isBalanced(root,depth);
}
bool isBalanced(TreeNode* root,int& depth) {//後序遍歷
    if(!root)
        return true;
    int diff=0,l=0,r=0;//都會經過isBalanced函式從而改變depth;
    if(isBalanced(root->left,l) && isBalanced(root->right,r))//本層的滿足返回true;
    {
        diff=abs(l-r);
        depth=max(l,r)+1;
        if(diff<=1)//滿足平衡就返回true
            return true;
    }
    return false;//本層不滿足就返回false
}

112.Path Sum 路徑總和
如果左右兒子均為NULL,返回:root->val==sum;
否則每一層減去該層val值,繼續遞迴;

bool hasPathSum(TreeNode* root, int sum) {//前序遍歷
    if(!root)
        return false;
    if(!root->left && !root->right)
        return root->val==sum;
    return hasPathSum(root->left,sum-root->val) || hasPathSum(root->right,sum-root->val);
}

113.Path Sum II 找到所有從根到葉路徑總和等於給定總和的路徑
未完待續…

129.Sum Root to Leaf Numbers 求根葉數字 總和
1.開新函式,傳遞subsum引數;2.前序遍歷,上一層和(subsum)加上本層的值:subsum*10+root->val

int sumNumbers(TreeNode* root) {
    return sum(root, 0);
}
int sum(TreeNode*root, int subsum) //需要子函式,父*10+子   //前序遍歷
{
    if(!root)   
        return 0;
    if(!root->left && !root->right) 
        return subsum*10+root->val;
    return sum(root->left, subsum*10+root->val)+sum(root->right, subsum*10+root->val);
}

226.Invert Binary Tree 翻轉二叉樹
前序遍歷,交換左右兒子即可

TreeNode* invertTree(TreeNode* root) {
   if(!root)
        return NULL;
    TreeNode* tmp=root->left;
    root->left=root->right;
    root->right=tmp;
    invertTree(root->left);
    invertTree(root->right);
    return root;
}

4.構造二叉樹

105.Construct Binary Tree from Preorder and Inorder Traversal 從前序與中序遍歷序列構造二叉樹
每次從 preorder 頭部取一個值 mid,作為樹的根節點檢查 mid 在 inorder 中的位置;則mid 前面部分將作為 樹的左子樹,右部分作為樹的右子樹
左子樹:
先序:左子根節點;右子根節點
中序: 左子樹的最左節點,當前根節點
右子樹:
先序:右子根節點;右子樹最後一個節點的尾後節點
中序:右子樹的最左節點;右子樹最後一個節點的尾後節點
前序構造
preorder: 8 [4 3 3 7] [5]
inorder: [3 3 4 7] 8 [5]

TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
    return helper(preorder,0,preorder.size(),inorder,0,inorder.size());
}
TreeNode* helper(vector<int>& preorder,int pi,int pj,vector<int>& inorder,int ii,int ij){
//前序構造
    if(pi >= pj || ii >= ij)

    int mid = preorder[pi];//1.preorder找到mid位置;pi為當前根節點位置
    auto f = find(inorder.begin() + ii,inorder.begin() + ij,mid);//2.inorder找到mid位置
    int nf = f - (inorder.begin() + ii);//3.以mid為根節點的左子樹節點個數

    TreeNode* root = new TreeNode(mid);    
    root -> left = helper(preorder, pi + 1, pi + 1 + nf,   inorder, ii, ii + nf); 
    root -> right = helper(preorder, pi + 1 + nf, pj,   inorder, ii + nf + 1, ij);

    return root;
}

106.Construct Binary Tree from Inorder and Postorder Traversal 從中序與後序遍歷序列構造二叉樹
每次取postorder的最後一個值mid,將其作為樹的根節點;
然後從inroder中找到mid,將其分割成為兩部分,左邊作為mid的左子樹,右邊作為mid的右子樹。
先序構造
Inorder : [3 4 6] 8 [9 10 11]
postorder: [3 6 4] [9 11 10] 8

TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {        
    return helper(inorder,0,inorder.size(),postorder,0,postorder.size());
}
TreeNode* helper(vector<int>& inorder,int i,int j,vector<int>& postorder,int ii,int jj)
{//先序構造
    if(i >= j || ii >= jj)
        return NULL;

    int mid = postorder[jj - 1];//1.postorder中mid的位置
    auto f = find(inorder.begin() + i,inorder.begin() + j,mid);//2.inorder中mid的位置
    int nf = f - inorder.begin() - i;//3.以mid為根節點的左子樹節點個數

    TreeNode* root = new TreeNode(mid);
    root -> left = helper(inorder,i,i + nf,postorder,ii,ii + nf);
    root -> right = helper(inorder,i + nf + 1,j,postorder,ii + nf,jj - 1);

    return root;
}

108. Convert Sorted Array to Binary Search Tree 將有序陣列轉換為二叉搜尋樹
開新函式遞迴;找到中間的作為每次根節點,保證平衡,然後先序構造

TreeNode* sortedArrayToBST(vector<int>& nums) {
    return sortedArrayToBST(nums, 0,nums.size()-1);
    //1.這裡可以為:nums.size(),相應的下面的函式也需要改變
}
TreeNode* sortedArrayToBST(vector<int>& nums, int i, int j)
{//先序構造
    if(i >= j) 
        return NULL; 
    //找到中間的作為每次根節點,保證平衡,然後先序遍歷
    int mid=(i+j)/2;

    TreeNode* root=new TreeNode(nums[mid]);
    root->left=sortedArrayToBST(nums, i, mid);//2.就在這改為mid-1
    root->right=sortedArrayToBST(nums, mid+1,j);
    return root;
}

5.二叉樹祖先問題

235.Lowest Common Ancestor of a Binary Search Tree 二叉搜尋樹的最近公共祖先
分三種情況:
1.左右各一個;(else return cur;)
2.都在左邊,cur=cur->left;(p->val < cur->val && q->val < cur->val)
3.都在右邊,cur=cur->right;(p->val > cur->val && q->val > cur->val)

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    TreeNode* cur=root;
    while(cur)
    {
        if(p->val < cur->val && q->val < cur->val)
            cur=cur->left;
        else if(p->val > cur->val && q->val > cur->val)
            cur=cur->right;
        else
            return cur;
    }
}

236. Lowest Common Ancestor of a Binary Tree 二叉樹的最近公共祖先
1.後序遞迴過程中,碰到p,q(root == p || root == q || root == NULL) 就返回root到上一層;
2.否則繼續遞迴,一直到底,left和right均不為空,返回root到上一層,否則返回非空的到上一層。

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    if (root == p || root == q || root == NULL) 
       return root;//遞迴到這截止(root || NULL)!!!
    TreeNode *left = lowestCommonAncestor(root->left, p, q);
    TreeNode *right = lowestCommonAncestor(root->right, p, q);
    //left && right 就返回 root,否則返回非空的那一個!!!
    return left && right ? root : left ? left : right;
}

6.其他型別題

96. Unique Binary Search Trees 節點組成的不同的二叉搜尋樹有多少種
動態規劃:
1.f[i]表示:有i個節點時,它有多少種不同形態的樹
2.f[i]=sum[i=0->i-1] f[i] * f[i-j-1];這裡i-1-j 減掉的1代表是根節點佔了一個位置
3.f[0]=1,f[1]=1;

int numTrees(int n) {
    if(n==0 || n==1)
        return 1;
    vector<int> f(n+1,0);
    f[0]=1;//初始值
    f[1]=1;//初始值
    for (int i = 2; i <= n; ++i) 
    {
        int t = 0;
        for (int j = 0; j < i; ++j)
            t += f[j] * f[i-j-1];
        f[i]=t;
    }
    return f[n];
}

114. Flatten Binary Tree to Linked List 二叉樹轉換連結串列

    1
   / \
  2   5
 / \   \
3   4   6
1
    \
     2
      \
       3
        \
         4
          \
           5
            \
             6

非遞迴,不用棧!
解析:從樹的右到左…

void flatten(TreeNode* root) {
    while (root) 
    {
        if (root->left && root->right) 
        {
            TreeNode* p = root->left;
            while (p->right)
                p = p->right;
            p->right = root->right;
        }
        if(root->left)
            root->right = root->left;
        root->left = NULL;
        root = root->right;
    }
}

222. Count Complete Tree Nodes 完全二叉樹的節點個數
1.求高度;
2.有大於一層的節點數:求最後一層的節點個數

p = root;
level = h - 2;
while(level >= 0){
    (1)找到**左子樹**最後一層的**最右邊**的節點!
    (2)left!=NULL時:說明左子樹是滿的,節點個數為:count+=2^level,再去計算右子樹(p = p->right;)!
    (3)否則 left!=NULL時:說明最後一層左子樹就不滿,就去計算左左子樹(p = p->left;)!
    (4)--level;  
}

3.最後一層看還有別的節點時(最後一層節點個數為單數的時候)++count;
4.return (1 << (h - 1)) + count - 1;(1 << level為:2^level)。
具體程式碼如下:

int countNodes(TreeNode* root) {
    if(!root) 
        return 0;
    TreeNode *p = root;
    int h = 0, count = 0, level;
    while(p) //1.求高度
    {
        p = p->left;
        h++;
    }

    p = root;
    level = h - 2;
    while(level >= 0) //2.求最後一層的節點個數!!!
    {
        TreeNode* left = p->left;

        for(int i = 0;i < level;i ++) //1.找到left子樹最後一層的最右邊的節點!
            left = left->right;
        if(left) //2.左子樹是滿的,就去計算右子樹!
        {
            p = p->right;
            count += (1 << level);//3.就是2^level
        } 
        else //4.left==NULL說明最後一層左子樹就不滿,就去計算左左子樹!
            p = p->left;
        --level;       
    }
    if(p) //3.此時就是一個根節點!!!
        count++;
    return (1 << (h - 1)) + count - 1;
}

230. Kth Smallest Element in a BST 二叉搜尋樹中第K小的元素
中序遍歷:if(–k == 0) return p->val;即可!!!

int kthSmallest(TreeNode* root, int k) {
    if(!root)
        exit(-1);
    while(p || !s.empty())
    {
        ...
        if(--k == 0)//找到第k小的value
            return p->val;
        ...
    }
}

1.二叉樹中序遍歷

94.Binary Tree Inorder Traversal 二叉樹中序遍歷
98.Validate Binary Search Tree 驗證二叉搜尋樹
99. Recover Binary Search Tree 恢復二叉搜尋樹

2.層遍歷

102 Binary Tree Level Order Traversal 二叉樹的層次遍歷
100.Same Tree 相同的樹
101.Symmetric Tree 對稱二叉樹
103.Binary Tree Zigzag Level Order Traversal 二叉樹的迴環層次遍歷
107.Binary Tree Level Order Traversal II 值自底向上的層次遍歷
116.Populating Next Right Pointers in Each Node 每個節點的右向指標
199.Binary Tree Right Side View 二叉樹的右檢視
515. Find Largest Value in Each Tree Row 在每個樹行中找最大值
637. Average of Levels in Binary Tree 二叉樹的層平均值

3.前序遍歷和後序遍歷

144.Binary Tree Preorder Traversal 二叉樹的前序遍歷
145.Binary Tree Postorder Traversal 二叉樹的後序遍歷
104.Maximum Depth of Binary Tree 二叉樹的最大深度
111.Minimum Depth of Binary Tree 二叉樹的最小深度
110. Balanced Binary Tree 平衡二叉樹
112.Path Sum 路徑總和
113.Path Sum II 找到所有從根到葉路徑總和等於給定總和的路徑
129.Sum Root to Leaf Numbers 求根葉 數字 總和
226.Invert Binary Tree 翻轉二叉樹

4.構造二叉樹

105.Construct Binary Tree from Preorder and Inorder Traversal 從前序與中序遍歷序列構造二叉樹
106.Construct Binary Tree from Inorder and Postorder Traversal 從中序與後序遍歷序列構造二叉樹
108.Convert Sorted Array to Binary Search Tree 將有序陣列轉換為二叉搜尋樹

5.二叉樹祖先問題

235.Lowest Common Ancestor of a Binary Search Tree 二叉搜尋樹的最近公共祖先
236. Lowest Common Ancestor of a Binary Tree 二叉樹的最近公共祖先

6.其他型別題

96. Unique Binary Search Trees 節點組成的不同的二叉搜尋樹有多少種
114. Flatten Binary Tree to Linked List 二叉樹轉換連結串列
222. Count Complete Tree Nodes 完全二叉樹的節點個數
230. Kth Smallest Element in a BST 二叉搜尋樹中第K小的元素