代码随想录算法训练营第二十天 | 530. 二叉搜索树的最小绝对差、501. 二叉搜索树中的众数、236. 二叉树的最近公共祖先

35 阅读5分钟

530. 二叉搜索树的最小绝对差

链接

文章链接

题目链接

第一想法

由于昨天做过搜索二叉树的题,所以立马就想到了用中序遍历,所以尝试用添加辅助数组的方式进行求解,代码如下:

 function getMinimumDifference(root: TreeNode | null): number {
    let res:number[]=[]
    const foo=(root: TreeNode | null)=>{
        if(root==null) return
        foo(root.left)
        res.push(root.val)
        foo(root.right)
    }
    foo(root)
    let num:number=Number.MAX_SAFE_INTEGER
    for(let i=1;i<res.length;i++){
        num=Math.min(res[i]-res[i-1],num)
    }
    return num
};

看完文章后的想法

文章用递归法和迭代法两种方案解决了这个问题,这里详细讲述递归法的两种方法,辅助数组法和双指针法。辅助数组法和上面我写的类型,下面的代码是双指针法,核心思想是记录递归节点的前一个节点,详细图为:

image.png 代码如下:

function getMinimumDifference(root: TreeNode | null): number {
    let pre:TreeNode|null=null
    let num:number=Number.MAX_SAFE_INTEGER
    const foo=(root: TreeNode | null)=>{
        if(root==null) return
        foo(root.left)
        if(pre!=null){
            num=Math.min(num,root.val-pre.val)
        }
        pre=root
        foo(root.right)
    }
    foo(root)
    return num
};

思考

由于昨天了解过搜索二叉树的性质,所以今天做这道题不是很难,目前能熟悉掌握递归法的辅助数组的方法,对于双指针法目前是第一次进行尝试,需要多加琢磨。

501. 二叉搜索树中的众数

链接

文章链接

题目链接

第一想法

因为是搜索二叉树,所以万能用辅助数组法可以解决,所以这道题尝试直接在递归中修改,核心思想是也是辅助数组,但是这个辅助数组是在递归中的,数组用于存储相同val,如果遇到不相同的val,则进行判断,看是否是众数,如果是则存储到res中,代码如下:

 function findMode(root: TreeNode | null): number[] {
    let res:number[]=[]
   let nums:number[]=[]
   let max=0 //记录达到多少个数才是众数
   const dfs=(root: TreeNode | null)=>{
       if(root==null) return
       dfs(root.left)
       if(nums.length>0&&root.val>nums[nums.length-1]){ //如果当前节点的数和存储的数不相同,则进行判断数组里面的数是不是众数
           if(max<nums.length){ //新的众数
               max=nums.length
               res=[nums[0]]
               nums=[]
           }else if(max==nums.length){//和res里面都是众数
                res.push(nums[0])
                nums=[]
           }else nums=[] //不是众数
       }
       nums.push(root.val)
       dfs(root.right)
   }
   dfs(root)
   if(max<nums.length) return [nums[0]]
   if(max==nums.length) res.push(nums[0])
    return res
};

看完文章后的想法

代码随想录中用了三种方法求解,总体分为两类:递归法和迭代法,递归法中有两种,应该是应对一般二叉树的解法,用map统计,最后转化为数组进行求解,这里给出针对二叉搜索树的解法,利用中序遍历和双指针的方法,可以得出结果,代码如下:

 function findMode(root: TreeNode | null): number[] {
    let res:number[]=[]
   let count:number=0 //计算相同元素的个数
   let pre:TreeNode|null=null
   let max:number=0
   const dfs=(root: TreeNode | null)=>{
       if(root==null) return
       dfs(root.left)
       if(pre==null){ //前一个节点为null则重置count
         count=1
       }else if(root.val==pre.val) count++ //当前节点val与前一个节点val相同 count++
       else count=1 //当前节点val与前一个节点val不相同 重置count
       if(count==max)  res.push(root.val) //用于判断是否是众数
       if(count>max){
           max=count
           res=[root.val]
       }
       pre=root
       dfs(root.right)
   }
   dfs(root)
    return res
};

思考

这道题不算很难,如果是一般二叉树直接用map进行统计后再求解,如果是搜索二叉树,就可以用二叉搜索树的性质进行求解,但是要注意pre为null和pre.val!=root.val的时候要重置,同时也要注意如何求众数,这是第一次尝试直接在递归过程中求解,值得纪念。

236. 二叉树的最近公共祖先

链接

文章链接

题目链接

第一想法

题目要求找到节点深度尽量大的公共节点,想法是用后序遍历,找到的话就返回true,如果左右节点都是true,则返回的就是公共节点。尝试一下:

function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
	const dfs=(root: TreeNode | null)=>{
        if(root==null) return false //终止条件
        let left:boolean|TreeNode=dfs(root.left) //获取左节点返回的值
        let right:boolean|TreeNode=dfs(root.right) //右节点返回的值
        if(root.val==q.val||root.val==p.val){//这个条件是判断 一个节点正好是他的祖先的情况
           return (left||right)?root:true //如果左右节点其中一个返回的是true 则返回当前节点(当前节点就是公共节点)
        } 
        if(left===true&&right===true){//这种是左右孩子都找到了符合q||p的节点,所以目前节点是最深公共节点
            return root
        }
        if(typeof left!='boolean' || typeof right !="boolean"){ //如果返回的是节点的话 直接返回这个节点
            return typeof left!='boolean' ?left :right
        }
        //一般情况 如果左右孩子找到了符合目标的节点 则返回true,否则返回false
        return left||right
    }
    return dfs(root)
};

看完文章后的想法

文章的核心思想和我的一样,都是利用后序遍历(包含回溯)的方法进行求解,唯一不同的情况是文章值的返回值只有Treenode|null,不包括boolean,所以解题思路有以下几点:

  1. 当前节点等于q或p的情况下 直接返回当前节点 (这种情况下包括有一个节点是公共节点的情况,后序条件中会体现)
  2. 如果当前节点为null 返回null
  3. 获取当前左右孩子的返回值 如果都返回null则说明里面并不包含q和p,所以返回null
  4. 如果左右孩子都有返回值且不为null 则当前节点为公共节点
  5. 如果左孩子不为null 右孩子为null 则返回左孩子(对照1)
  6. 如果左孩子为null 右孩子不为null 则返回右孩子(对照1) 详细代码如下:
function lowestCommonAncestor(root: TreeNode | null, p: TreeNode | null, q: TreeNode | null): TreeNode | null {
	const dfs=(root: TreeNode | null)=>{
        if(root==null||root==q||root==p) return root
        let left:TreeNode|null=dfs(root.left)
        let right:TreeNode|null=dfs(root.right)
        if(left!=null&&right!=null) return root
        if(left==null) return right
        if(right==null) return left
    }
    return dfs(root)
};

思考

这道题不太好像,自己虽然写出来了,但是思路没有那么清晰,自己懵懵懂懂的做出来了,文章配图加文字很好的讲解了这道题,如果大家看不懂我的思路,可以去代码随想录中查看更详细的文章讲解。

今日总结

今日耗时2.5小时 三道题各有各的不同,第一道题依靠昨天的想法很容易就写出来了,第二道题尝试不使用辅助的方法进行求解。第三道题懵懵懂懂的做出来了,但是文章帮助我很清晰耳朵理解了思路,总得来说,今天收获巨大。