简单编程题目连载(十五)——找二叉树中的最大搜索二叉子树
2017-02-06 22:06
399 查看
什么是搜索二叉树,每棵子树的头节点的值都比各自左子树上的所有节点值要大,也都比各自右子树上的所有节点值要小。
最好判断的一种方法是,中序遍历二叉树,遍历结果整个序列为升序,那么这棵树为搜索二叉树,也叫二叉查找树,二叉排序树。
那么本题题目为:给定一颗二叉树的头节点head,已知其中所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这颗子树的头节点。
注意,给定的二叉树不一定是搜索二叉树,但整棵树一定有搜索二叉树,并且可能不止一个,需要找到节点数最多的那个。
很容易想到的思路是:遍历整颗树,把每一个节点当做头节点进行一次中序遍历,判断是否为搜索二叉树,并记录下这颗树的节点数,如果是搜索二叉树,保存该节点数和该头节点,然后继续遍历下一个节点,继续判断。
这个思路非常容易形成代码,并且是对的。整个代码如下:
很明显这个办法相对来说复杂度更高,不过容易理解,刚开始接触这个题可以试试这个办法。
当然还有另一种办法,并且对于大部分二叉树的题目来说,遍历肯定是少不了的。而且对于在二叉树中间查找些什么,那么后序遍历一定是最好的。因为可以从最深处开始,方便一层一层的判断。那么这个办法的思路如下:
找二叉树中最大搜索二叉子树无非两种情况
第一种:遍历到该头节点,该头结点的左孩子是所对应的左子树的最大搜索二叉子树的节点,该头节点的右孩子是所对应的的右子树的最大搜索二叉子树的节点。并且该头结点的值比左边整个子树的最大值还要大,比右边整个子树的最小值还要小,那么该头节点所代表的整颗树即为最大搜索二叉子树,返回头节点即可。
第二种:不满足第一种情况条件的,说明头节点不在搜索子树中,这时比较头节点左孩子代表的左搜索子树和右孩子代表的右搜索子树中,节点多的那个就是最大搜索二叉子树。
具体的过程描述如下:
进行二叉树的后序遍历,遍历的每个节点记录四个信息,该节点(TreeNode)、节点数、节点中的最大值、节点中的最小值。并且左右孩子节点分别记录。用所收集的信息判断是否满足第一种情况。如果不满足,就更新节点的最大值与最小值,并返回节点数多的那个头节点。
这个过程的困难之处在于如何每次返回四个信息,可以使用全局变量,或设立一个数组即可。
代码如下:
最好判断的一种方法是,中序遍历二叉树,遍历结果整个序列为升序,那么这棵树为搜索二叉树,也叫二叉查找树,二叉排序树。
那么本题题目为:给定一颗二叉树的头节点head,已知其中所有节点的值都不一样,找到含有节点最多的搜索二叉子树,并返回这颗子树的头节点。
注意,给定的二叉树不一定是搜索二叉树,但整棵树一定有搜索二叉树,并且可能不止一个,需要找到节点数最多的那个。
很容易想到的思路是:遍历整颗树,把每一个节点当做头节点进行一次中序遍历,判断是否为搜索二叉树,并记录下这颗树的节点数,如果是搜索二叉树,保存该节点数和该头节点,然后继续遍历下一个节点,继续判断。
这个思路非常容易形成代码,并且是对的。整个代码如下:
public TreeNode getMax(TreeNode root) { ArrayList<Integer> arr = new ArrayList<>(); Stack<TreeNode> s = new Stack<TreeNode>(); s.add(root); TreeNode goal = null; int max = 0; while(!s.isEmpty()){ root = s.pop(); midOrder(root,arr); boolean boo = tree(arr); if(arr.size() > max && boo){ max = arr.size(); goal = root; arr.clear(); }else{ arr.clear(); } if(root.left != null){ s.push(root.left); } if(root.right != null){ s.push(root.right); } } return goal; } public boolean tree(ArrayList<Integer> arr){ for(int i = 0; i < arr.size()-1; i++){ if(arr.get(i) > arr.get(i+1)){ return false; } } return true; } public void midOrder(TreeNode root,ArrayList<Integer> arr){ if(root == null){ return; } midOrder(root.left,arr); arr.add(root.val); midOrder(root.right,arr); }
很明显这个办法相对来说复杂度更高,不过容易理解,刚开始接触这个题可以试试这个办法。
当然还有另一种办法,并且对于大部分二叉树的题目来说,遍历肯定是少不了的。而且对于在二叉树中间查找些什么,那么后序遍历一定是最好的。因为可以从最深处开始,方便一层一层的判断。那么这个办法的思路如下:
找二叉树中最大搜索二叉子树无非两种情况
第一种:遍历到该头节点,该头结点的左孩子是所对应的左子树的最大搜索二叉子树的节点,该头节点的右孩子是所对应的的右子树的最大搜索二叉子树的节点。并且该头结点的值比左边整个子树的最大值还要大,比右边整个子树的最小值还要小,那么该头节点所代表的整颗树即为最大搜索二叉子树,返回头节点即可。
第二种:不满足第一种情况条件的,说明头节点不在搜索子树中,这时比较头节点左孩子代表的左搜索子树和右孩子代表的右搜索子树中,节点多的那个就是最大搜索二叉子树。
具体的过程描述如下:
进行二叉树的后序遍历,遍历的每个节点记录四个信息,该节点(TreeNode)、节点数、节点中的最大值、节点中的最小值。并且左右孩子节点分别记录。用所收集的信息判断是否满足第一种情况。如果不满足,就更新节点的最大值与最小值,并返回节点数多的那个头节点。
这个过程的困难之处在于如何每次返回四个信息,可以使用全局变量,或设立一个数组即可。
代码如下:
public TreeNode getMax(TreeNode root){ int[] record = new [3]; return posOrder(root,record); } public TreeNode posOrder(TreeNode root,int[] record){ if(root == null){ record[0] = 0; record[1] = 0; record[2] = 0; return null; } int value = root.val; Node left = root.left; Node right = root.right; Node lBst = posOrder(root.left,record); int lSize = record[0]; int lMax = record[1]; int lMin = record[2]; Node rBst = posOrder(root.right,record); int rSize = record[0]; int rMax = record[1]; int rMin = record[2]; if(left == lBst && right == rBst && lMax < value && value < rMin){ record[0] = lSize + rSize + 1; return root; } record[1] = Math.max(rMax,value); record[2] = Math.min(lMin,value); record[0] = Math.max(lSize,rSize); return lSize > rSize ? lBst : rBst; }
相关文章推荐
- 简单编程题目连载(二)
- 简单编程题目连载(七)——经典台阶问题
- 简单编程题目连载(三)
- 找到二叉树中的最大搜索二叉子树
- 简单编程题目连载(五)——找零钱
- 找到二叉树中的最大搜索二叉子树
- 简单编程题目连载(十)——公共最长子序列
- 数据结构 找到二叉树中的最大搜索二叉子树
- 简单编程题目连载(六)——找零钱
- 简单编程题目连载(十二)——最优编辑问题
- 简单编程题目连载(十三)——拓扑结构相同子树判断
- 简单编程题目连载(十一)——0-1背包问题
- 简单编程题目连载(八)——最短路径问题
- 简单编程题目连载(四)——找零钱
- 简单编程题目连载(一)
- 【编程题目】求二叉树中节点的最大距离
- 二叉树问题---找到二叉树中的最大搜索二叉子树
- 算法 Longest Repeated Sequence(最大重复子序列 微软编程一小时 题目2)
- 编程之美3.8求二叉树中节点的最大距离
- 二叉树-c#求解-英雄会在线编程题目