赞
踩
我第一时间想到的方法是遍历二叉树+哈希。哈希用来统计数字出现的次数。之后遍历map收集结果。
坏处就是效率比较低
class Solution { Map<Integer,Integer> map = new HashMap<>(); public int[] findMode(TreeNode root) { dfs(root); int mostValue = Integer.MIN_VALUE; List<Integer> result = new ArrayList<>(); for(Map.Entry<Integer,Integer> entry : map.entrySet() ){ int currentCount = entry.getValue(); if(currentCount>mostValue){ mostValue = currentCount; } } //找出最大的出现次数了。接下来做匹配去找符合这个次数的元素 for(Map.Entry<Integer,Integer> entry : map.entrySet()){ if(entry.getValue()==mostValue){ result.add(entry.getKey()); } } //如果不喜欢这个方法,也可以用传统方法,遍历List收集结果 return result.stream().mapToInt(Integer::intValue).toArray(); } void dfs(TreeNode root){ if(root==null){ return; } //这个方法比较常用,我当时想用没记起来 //这个是如果获取出来为空,那就给他赋一个默认值。 int count = map.getOrDefault(root.val,0); map.put(root.val,count+1); dfs(root.left); dfs(root.right); } }
高效的做法
利用了BST的性质,即BST的中序序列是有序序列
这个也是本题学到的一个很好的知识点。
class Solution { ArrayList<Integer> res = new ArrayList<>(); int count=0; int maxCount = Integer.MIN_VALUE; TreeNode pre = null; void dfs(TreeNode root){ //递归出口 if(root==null){ return; } //中序遍历,所以先递归左子树 dfs(root.left); //这里才是处理根节点 if(pre!=null && root.val==pre.val){ //这里表明与前一个节点值相等,所以累计众数 count++; }else{ //能到这里说明,pre=null即树的根节点,或者root.val!=pre.val即是新的不同节点 count = 1; } if(count==maxCount){ //如果计数达到了最大值,就加入结果集 res.add(root.val); } if(count>maxCount){ //说明超过了最大值,由于众数可能有多个,所以之前收集的最大值就不是最大值了 //所以之前收集的结果集要清空 res.clear(); //更新最新的最大值 maxCount = count; //把当前的这个新众数加入结果集 res.add(root.val); } //更新前一个节点为当前root,因为root要递归到下一个地方去了。当前节点已经处理完 //所以对即将遍历下一个节点而言,pre是当前root。 pre = root; dfs(root.right); } public int[] findMode(TreeNode root) { dfs(root); //收集结果 int size = res.size(); int[] ans = new int[size]; for(int i = 0;i<size;i++){ ans[i]=res.get(i); } return ans; } }
就是利用BST的中序序列有序的性质。结果最小绝对值差肯定在序列相邻元素之间。所以这题的思路和上题差不多,就是中序遍历,并且遍历的时候计算currentNode和preNode的差值。
class Solution { TreeNode pre = null; int min = Integer.MAX_VALUE; public int getMinimumDifference(TreeNode root) { dfs(root); return min; } void dfs(TreeNode root){ if(root==null){ return; } dfs(root.left); if(pre!=null){ //不等于null那么就二者之间计算一下差值 int sub = root.val-pre.val; //然后做一下正负判断 int currenSub = 0; if(sub<0){ currenSub = -sub; }else{ currenSub = sub; } //然后准备判断更新min if(currenSub<min){ min = currenSub; } } pre = root; dfs(root.right); } }
今天遇到的最难的题目。代码很简短,但是理解很痛苦。
首先需要明确的一点,手算我们都清楚,公共节点怎么找,那就是先看图,然后找到两个目标节点,然后往上找他们第一个交汇的节点,那么这个节点就是他的最近公共祖先节点。
所以从这个过程来看,找公共节点,还是应该用后序遍历,即先深入某点的左右子树,最后到根节点来判断。
知道了用哪种递归方式,那么就要清楚在递归的过程中,如何进行判断哪个节点是最近公共祖先。
判断公共祖先,需要通过分类来完成。
也许看完这个你还是很懵,感觉像在背套路,那么就跟着代码来模拟一下。
在模拟之前需要明确,用的是后序。所以最近公共祖先结果的处理是从底部开始的。
class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { //这个是递归出口,这里不但是递归出口,还做了剪枝。 //我觉得在想递归出口的时候,要联系上一层来看,不然会很懵。这就相当于提前为上一层返回结果了。 if(root == null || root == p || root == q) return root; //后序遍历递归左右子树 TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); //这里处理结果非常的精妙 //这三行代码甚至包括了三种情况,如果始终返回left或者right,那么这代表了p是q的最近祖先或者q是p的最近祖先。 //但是如果返回的过程中,碰到了left,right都不为null,也就是返回root。那么结果就变成了,某个节点是p和q的最近公共祖先的情况,然后把该点的结果一直向上传递。 if(left == null) return right; if(right == null) return left; return root; } }
这个题相比上一题难度小很多,依据二叉搜索树的性质,直接解决。
如果p,q的值都比root小,那么p,q在root的左子树,那么往左子树去递归寻找。反之如果p,q的值都比root大,那么p,q在root的右子树,那么去递归右子树去找。
那么剩下就包含了符合结果的三种情况。
1.p或q为最近公共祖先
2.p<root<q或p>root>q。
此时root都是最近公共祖先。所以返回root。
class Solution {
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
if(p.val<root.val && q.val<root.val){
return lowestCommonAncestor(root.left,p,q);
}else if(p.val>root.val && q.val>root.val){
return lowestCommonAncestor(root.right,p,q);
}else{
return root;
}
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。