力扣 | 二叉树刷题笔记

搜索二叉树

搜索二叉树

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x
的深度尽可能大(一个节点也可以是它自己的祖先)。”

解题思路:
搜索二叉树的的性质就是对于任意一个结点,它的左子树所有值都要比它小,右子树的所有结点值都要比它大。

既然是二叉搜索树,那么root结点的值和pq的值肯定有大小关系。 遍历过程中有三种情况:

  1. 是在发现当前结点的值和p,q任意一个相等,
  2. 发现当前结点比p,q都大/都小。
  3. 发现当前结点比其中一个大,其中一个小
  • root结点的值比p和q都大时,就说明p,q结点肯定在root的左子树上,于是直接遍历左子树
  • 当root结点的值比q和p小时,说明q和p在右子树上,于是遍历右子树
  • 如果在遍历中发现root结点和q和p任意一个相等,直接可以判断这个root结点就是他们的公共祖先
  • 当root结点比其中一个大,其中一个小,说明这两个结点在root的左右子树中, root也是他们的最近公共祖先。

总结:本题目就是要求我们熟悉搜索二叉树的性质,并规划好dfs的路径。

代码实现:

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null) return null ;
        TreeNode s= dfs(root,p,q) ;
        return s; 
    }
    private TreeNode dfs(TreeNode root, TreeNode p, TreeNode q){
        if(root==null)  return  null ;
        //在左右子树中 
        if( ( root.val>p.val &&root.val<q.val )|| (root.val <p.val && root.val > q.val) ) return root ;
        // p或q 
        if(root.val==p.val || root.val==q.val) return root  ;
        // root的值比p,q都大,去左子树
       if(root.val>p.val && root.val>q.val)   
            return lowestCommonAncestor(root.left, p,q) ;
      // root的值比p,q都大,去右子树
        if(root.val<p.val && root.val<q.val) 
            return lowestCommonAncestor(root.right, p, q) ;
        return null ;        
   }
}


/*******************非递归版本:可以参考************************/
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null) return null ;
        TreeNode s =root; 
        while(true) {
            if(p.val < s.val && q.val<s.val) 
                s=s.left;
            else if(p.val>s.val&&q.val>s.val)
                s=s.right;
            else break; 
        }
        return s; 
    }
}


思考
其实这道题一旦分析到上面的3种情况,实现就不难了,但是要分析出来,需要对搜索二叉树这种数据结构有一定理解。

填充每一个结点的下一个右侧指针

力扣117.
读题,想用dfs加前中后三种遍历方式来做,做不出来,只好灰溜溜地看了题解,发现是bfs,一方面骂自己菜,又悄悄庆幸好没有浪费太多的时间在错误的方向上。
唉,悲喜交加的刷题生涯。。。 (PS: 最近做题虽然做了记录发了博客,都没啥人看,反正写的不好,就当写日记一样记录我的垃圾大二青春把。。。)

思路
按照题解的思路,这种需要考虑同一层结点的题目,最好的方法还是使用bfs的层序遍历。

层序遍历一般都要用到队列,我再做题的时候,又陷入了如何记录这一层的结点个数的问题,原来直接用了queue.size()来表示当前一层的结点个数 。
在遍历的时候,记录结点pre,指向后面poll出来的结点。

class Solution {
    public Node connect(Node root) {
        if(root==null) return root ;
        Deque<Node> list=new LinkedList<Node>() ;
    
        list.offerLast(root); 
        while(!list.isEmpty ()){
            Node pre=null ;
            int size =list.size() ;
            for(int i=0 ;i<size;i++) {
                Node cur=list.poll() ;
                if(pre!=null) pre.next =cur  ;
               
                pre=cur  ;
               
                if(cur.left !=null) list.offerLast(cur.left) ;
                if(cur.right !=null) list.offerLast(cur.right) ;
            }
           
        }
        return root ;
    } 
}

把二叉搜索树转换成累加树

力扣538.

给出二叉 搜索 树的根节点,该二叉树的节点值各不相同,修改二叉树,使每个节点 node 的新值等于原树中大于或等于 node.val
的值之和。 示例:

在这里插入图片描述

解题过程:
我们知道解决树的问题其实就是靠遍历,前序,中序,后序和层序遍历,前三种遍历的不同点只在于访问的时机不同。

二叉搜索树有个特别的性质,中序遍历得到是一个递增的序列。

分析:对一个结点,要做的事情就是:将它的右子树所有的和加到自己身上,再将它的值加到左子树的各个结点上。 所以访问的路径就是: 右子树–>根结点–>左子树,代码表示如下:

dfs(root.right); 
...//要做的动作
dfs(root.left);

我们可以设置一个变量,这个变量就随着递归函数游走在每一结点上,从右子树最右边的叶子开始有顺序地累每一个结点,返回的时候就将这个变量累加到当前结点上,这样就实现了将整棵树有顺序计划地加值。


class Solution {
    int num=0;
    public TreeNode convertBST(TreeNode root) {
        if(root==null) return root;
        convertBST(root.right) ;
        root.val+=num;
        num= root.val;
        convertBST(root.left) ;
        return root ;
    }
    
}

最后总结

这道题的定位是easy ,逻辑也不难懂,最核心的部分就是实现。(我在做这道题的时候,就没有设置变量,有些结点就没有加全)个人觉得,使用递归不难,在递归中还要使用一些变量就比较难受,经验太少,不懂得如何设置好变量。

最大二叉树

力扣654.最大二叉树

解题思路:

  • 题目要求每次都在数组里寻找最大的元素,将该元素作为根节点,该元素右边的序列作为右子树,左边的序列作为左子树。

  • 本题建树的过程,本身就是一个递归的过程,用同样的动作确定根节点,确定左右子树。

public class Solution {
    private int findIndex(int[] arr, int start , int end  ){
        int idx =start, num = -1 ;
        for(int i=start ;i<end ;i++){
            if (arr[i]>num){
                idx= i ;
                num = arr[i] ;
            }
        }
        return idx ;
    }
    private TreeNode recursive(int [] nums,int start,int end) {
        if(start>=end){
            return null ;
        }
        int idx = findIndex(nums, start,end);
        TreeNode root = new TreeNode(nums[idx]); 
        root.left= recursive(nums,start, idx) ;
        root.right = recursive(nums,idx+1,end) ;
        return root ;

    }
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        return recursive(nums, 0, nums.length-1);
        
    }
}

重建二叉树

剑指offer0.7

输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值