LeetCode总结,二叉树各种类型问题小结

1,三大基础遍历方式

三个遍历的博客地址,

1)<LeetCode OJ> 144/145/94 Binary Tree (Pre & In & Post) order Traversal

即:

前序遍历,总是先访问当前节点,再左子,最后右子

中序遍历,总是先访问左子,再当前节点,最后右子

后序遍历,总是先访问左子,再右子,最后当前节点

关于三大基础遍历,必须要条件反射式的记住:三种遍历的迭代方式使用的都是,后序遍历必须使用了两个栈,其余乱七八糟的解决方式统统就不要再记了


2,广度遍历

三道中序遍历题目:

1)<LeetCode OJ> 102. / 107. Binary Tree Level Order Traversal(I / II)

分析:

102题目的意思是每一层均按照从左到右的顺序遍历节点,并记录节点到vector中。显然广度优先搜索,用队列。

利用两个队列保存当层的节点与下一层的节点,下一层的元素处理完后,

下一层成为当层(继续获取下一层的节点)。

107题目道理是一样的,不过就是插入vector的顺序逆着来而已,不过这样做似乎没有达到考察的目的!


2)<LeetCode OJ> 103. Binary Tree Zigzag Level Order Traversal

这个问题和上面的题目基本一样,唯一的区别就是奇数层和偶数层的压入顺序相反而已,但是通过vector插入顺序的不同来达到目的似乎并没有达到题目的考察目的。


102/103/107三个题目,都是按照广度优先遍历二叉树,其实主要用到数据结构队列。算法这里不细说了,可以直接看文章中的代码。

显然,中序遍历必须要条件反射的是,务必使用数据结构队列


3,构造二叉树

1)<LeetCode OJ> 106. Construct Binary Tree from Inorder and Postorder Traversal
2)<LeetCode OJ> 105. Construct Binary Tree from Preorder and Inorder Traversal

分析:

首先要弄清楚什么是前序遍历和中序遍历,后续遍历?
前序遍历就是先遍历当前的节点,然后遍历该节点的左分支(即遍历左分支的所有节点),最后再遍历该节点的右分支。
中序遍历是先遍历当前节点的左分支,再遍历当前节点,最后遍历当前节点的右分支。

还有后序遍历,就是先左分支,再右分支,最后当前节点。

以下面的二叉树为例。
         4
        / \
      2    7
     /  \  /  \
    1  3 6   9
其先序遍历结果:【4 2 1 3 7 6 9】
中序遍历结果是:【1 2 3 4 6 7 9】

后序遍历结果是:【1 3 2 6 9 7 4】


对先序遍历来说:
先序遍历的每个值表示的结点都是接下来的若干个结点(根据中序遍历即确定)的父结点。
比如【4】是这个二叉树的根结点,【2】是【1 3】的父结点,【1】是 空的父结点,也即使叶子结点。


对中序遍历来说:
根结点(根据前序遍历即确定)一定在中间位置,该位置左边是其左子树,右边是其右子树。
比如【4】左边【1 2 3】全是根结点的左子树,右边是【6 7 9】是根结点的右子树。
对于【2】来说,【1】是其左子树,【3】是其右子树。


对后序遍历来说:
后序遍历的末尾结点都是前面的若干个结点(根据中序遍历即可确定)的父结点。
比如【4】是这个二叉树的根结点,【2】是【1 3】的父结点,【7】是【4 6】的父结点,


……
依次类推。
很明显,这是一个递归过程。


4,二叉树的平衡

博文地址:
1)判断一颗二叉树是否平衡,<LeetCode OJ> 110. Balanced Binary Tree
2)根据有序链表和数组构造二叉搜索树,<LeetCode OJ> 109 / 108 Convert Sorted ( List / Array ) to Binary Search Tree

有序数组或者链表转化成二叉搜索树。思路还是比较明显的!因为有序,为了能平衡,总是选择数组或者(未被使用过的位置的)中间位置的值作为当前二叉树的根节点!显然对于链表来说就是使用快慢指针法来找到中间位置。



5,枚举二叉搜索树

见博文:
1)符合要求的二叉搜索树有多少种?,<LeetCode OJ> 96. Unique Binary Search Trees

这个问题实际上是动态规划问题,所以必须努力去找到和以前的子问题的联系。
断言:由1,2,3,...,n构建的二叉查找树,以i为根节点,左子树由[1,i-1]构成,其右子树由[i+1,n]构成。
定义子问题:定义f(i)为以[1,i]能产生的二叉搜索树的数目
若数组为空,则只有一种BST,即空树,f(0)=1;
若数组仅有一个元素1,单个节点,f(1)=1;
若数组有两个元素1,2,则有两种可能,f(2)=2;
若数组有三个元素1,2,3,则有5中情况,题目已经说了,
n=4呢?显示此问题玄机的时候到了:寻找与上面已推出子问题的关系:
如果1为根,则左子树0个元素所以1种情况,右子树3个元素(2,3,4),显然为5种情况
如果2为根,则左子树1个元素所以1种情况,右子树2个元素(3,4),显然为2
如果3为根,则左子树2个元素所以2种情况,右子树1个元素(4),显然为1
如果4为根,则左子树3个元素所以5种情况,右子树3个元素(无),显然为1
由此可以得到递推公式:f(i)=f(0)*f(i-1)+...+f(k-1)*f(i-k)+...+f(i-1)*f(0)


2,Unique Binary Search Trees II


6,二叉树结构变更

博文如下:

1)反转二叉树,<LeetCode OJ> 226. Invert Binary Tree

2)二叉树是否镜像对称?,<LeetCode OJ> 101. Symmetric Tree
3)将二叉树碾平成单链表,<LeetCode OJ> 114. Flatten Binary Tree to Linked List

4)右视二叉树的结果, <LeetCode OJ> 116 / 117 Populating Next Right Pointers in Each Node (I / II)


7,结构特征判断

两颗二叉树是否一样,

1)<LeetCode OJ> 100. Same Tree


8,二叉树路径判断

1)<LeetCode OJ> 235. / 236. LCA of a BSTree & BTree
对于235题,因为是在一颗二叉搜索树中(左右子具有大小关系),那么我们只需要关注祖先节点r和q、p的关系即可!

注意:本题给定的两个节点一定在这个二叉搜索树上,所以一定存在最低公共祖先。

如果当前节点r是q和p的祖先,一定满足如下条件:
 1)p和q分居两颗子树
 2)p和q中有一个就是当前节点,另一个居于某颗子树
 那么其他情况呢?
 3)p和q都在左子树或者右子树

 而根据二叉搜索树的规则,我们可以通过比较三个节点的大小来判断谁在谁的那一边


对于236题:思路就是记录从根节点达到p和q的两条路径,显然知道了两条路径之后,不相同的上一个节点就是最低公共祖先。
比如4和2的:
4的路径:3,5,2,4
2的路径:3,5,2





<LeetCode OJ> 129. Sum Root to Leaf Numbers

Total Accepted: 74843  Total Submissions: 229553  Difficulty: Medium

Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number.

An example is the root-to-leaf path 1->2->3 which represents the number 123.

Find the total sum of all root-to-leaf numbers.

For example,

    1
   / \
  2   3

The root-to-leaf path 1->2 represents the number 12.
The root-to-leaf path 1->3 represents the number 13.

Return the sum = 12 + 13 = 25.


分析:DONE

深度优先搜索!累加当前节点的值,一旦遇到叶子就加到sum里,最后统计出总和!

[cpp]  view plain  copy
 print ?
  1. /** 
  2.  * Definition for a binary tree node. 
  3.  * struct TreeNode { 
  4.  *     int val; 
  5.  *     TreeNode *left; 
  6.  *     TreeNode *right; 
  7.  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {} 
  8.  * }; 
  9.  */  
  10. class Solution {  
  11. public:  
  12.     int sumNumbers(TreeNode* root) {  
  13.         m_nsum=0;  
  14.         if(root==NULL)  
  15.             return m_nsum;  
  16.         dfs(root,0);  
  17.         return m_nsum;  
  18.     }  
  19.     void dfs(TreeNode* pnode,int curval)  
  20.     {  
  21.         if(pnode->left==NULL && pnode->right==NULL)  
  22.         {  
  23.             m_nsum+=10*curval+pnode->val;  
  24.             return;  
  25.         }  
  26.         if(pnode->left!=NULL)  
  27.             dfs(pnode->left,10*curval+pnode->val);  
  28.         if(pnode->right!=NULL)  
  29.             dfs(pnode->right,10*curval+pnode->val);      
  30.     }  
  31.       
  32. private:  
  33.     int m_nsum;  
  34. };  


<LeetCode OJ> 199. Binary Tree Right Side View


Total Accepted: 40438  Total Submissions: 117654  Difficulty: Medium

Given a binary tree, imagine yourself standing on the right side of it, return the values of the nodes you can see ordered from top to bottom.

For example:
Given the following binary tree,

   1            <---
 /   \
2     3         <---
 \     \
  5     4       <---

You should return [1, 3, 4].


分析:

典型的广度优先遍历,每一层的最右边那个元素显然就是当层的右视可见节点!

[cpp]  view plain  copy
 print ?
  1. /** 
  2.  * Definition for a binary tree node. 
  3.  * struct TreeNode { 
  4.  *     int val; 
  5.  *     TreeNode *left; 
  6.  *     TreeNode *right; 
  7.  *     TreeNode(int x) : val(x), left(NULL), right(NULL) {} 
  8.  * }; 
  9.  */  
  10. class Solution {  
  11. public:  
  12.     vector<int> rightSideView(TreeNode* root) {  
  13.         if(root==NULL)    
  14.             return result;    
  15.         queue<TreeNode *> que;    
  16.         que.push(root);    
  17.         //广度优先,总是压入每一层最右边的即可  
  18.         while(!que.empty())    
  19.         {    
  20.             int levelNum = que.size();//通过size来判断当层的结束     
  21.             for(int i=0; i<levelNum; i++)       
  22.             {      
  23.                 if(que.front()->left != NULL) //先获取该节点下一层的左右子,再获取该节点的元素,因为一旦压入必弹出,所以先处理左右子      
  24.                     que.push(que.front()->left);      
  25.                 if(que.front()->right != NULL)       
  26.                     que.push(que.front()->right);      
  27.                 if(i== (levelNum-1))          
  28.                     result.push_back(que.front()->val);      
  29.                 que.pop();      
  30.             }  
  31.               
  32.         }    
  33.         return result;    
  34.     }  
  35. private:  
  36.      vector<int> result;  
  37. };  



参考资源:

【1】http://blog.csdn.net/loverooney/article/details/32340299


注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!

原文地址:http://blog.csdn.net/ebowtang/article/details/51488374

原作者博客:http://blog.csdn.net/ebowtang

本博客LeetCode题解索引:http://blog.csdn.net/ebowtang/article/details/50668895

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值