【刷题日记】99. 恢复二叉搜索树

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情

一、题目描述:

恢复搜索二叉树, 咱们来看看需要咱们如何去恢复

二、这道题考察了什么思想?你的思路是什么?

仔细看题目,看上去像是节点被交换了,实际上题目描述的是这颗树正好有 2 个节点的值被交换了,因此我们思考的方向首先得正确,接下来思考才会更加有有效

  • 第一,题目说明正好有 2 个节点被交换了,我们知道这俩节点,可能是按照顺序前一个和后一个交换了,也有可能间隔的比较长
  • 第二,题目要求我们不要改变二叉树的结构,因此,我们可不要想着去对二叉树进行旋转或者去调整二叉树节点的指向了

分析

看了上述情况,我们不能去改变二叉树的结构,但是题目又要我们恢复二叉树搜索树,那么我们可以从交换节点的值着手

我们知道二叉搜索树,实际上就是按照中序遍历二叉树,得到的结果是一个有序的数组,那么这棵树就是一颗二叉搜索树,通过眼睛直观的可以看到,二叉搜索树中节点的左子树一定是不会大于当前节点,当前节点的值一定不会大于他的右子树

那么,我们从交换节点的值出发,那么咱们就需要先找到需要交换的 2 个节点具体是什么,然后再进行值的交换即可

正如题目中的示例一样

咱们中序遍历出来的结果是:321 , 对于这个数组我们知道 1 和 3 的位置错了,因此我们需要交换 1 和 3 对应节点的值,变成 123

那我们对于遍历完成的二叉树,得到的数组,如何去找到这两个错误位置的节点呢?

例如

1 6 3 4 5 2

其实我们只需要遍历数组的时候,判断当前数字的后一个数小于当前数字,若符合的话,那么实际上已经定位到一个错误的位置了,这个时候,我们可以将后一个数字的索引记录为 idx2,当前位置的索引记录为 idx1 , 例如上述的 idx1 就为 1,idx2 就为 5

这个时候,最终,我们就可以得到一个 idx1 和 idx2 对应的数字,最终遍历二叉树,进行交换即可

三、编码

根据上述逻辑和分析,我们就可以翻译成如下代码

咱们编码的思路强调一波,和上述分析的一致

  • 第一先中序遍历拿到目前树的数据排序
  • 找到数组中被错误调换的 2 个数字
  • 交换这两个数字,不要改变树中节点的指针指向

编码如下:

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
 
func recoverTree(root *TreeNode)  {
    // 1、遍历获取当前二叉搜索树的数据
    nums := []int{}
    var dfs func(root *TreeNode)
    dfs = func(root *TreeNode){
        if root == nil{
            return
        }
        dfs(root.Left)
        nums = append(nums, root.Val)
        dfs(root.Right)
    }
    dfs(root)
    // 2、找到被交换的 2 个节点
    x,y := findData(nums)
    // 3、交换数据
    mySwap(root,x,y,2)
}
func findData(nums []int)(int,int){
    // 定义 被错误交换 2 个数字的初始化为一个小于 0 的值
    // 例如案例数组为 163452,我们知道 idx1 就为 1,idx2 就为5
    idx1, idx2 := -1,-1
    for index := 0; index<len(nums)-1; index++ {
        if nums[index+1] < nums[index] {
            idx2 = index+1
            if idx1 == -1 {
                idx1 = index
            }else{
                break
            }
        }
    }
    return nums[idx1], nums[idx2]
}

func mySwap(root *TreeNode, x,y,count int){
    if root == nil {
        return 
    }
    if root.Val == x || root.Val == y {
        if root.Val == x {
            root.Val = y
        }else{
            root.Val = x
        }
        count--
        if count == 0 {
            return
        }
    }
    mySwap(root.Left, x, y, count)
    mySwap(root.Right, x, y, count)
    return
}
复制代码

四、总结:

咱们这种解决方式的话,可以看得出来思路比较简单,但是,咱们使用了一个 nums ,占用了一定的空间,空间复杂度是 O(n),

时间复杂度为 O(n) ,咱们做了一次中序遍历,遍历了 n 个节点,另外我们还遍历了 nums 数组,总的来说时间复杂度是 O(n) 级别的

原题地址:99. 恢复二叉搜索树

今天就到这里,学习所得,若有偏差,还请斧正

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞关注收藏,下次见~

猜你喜欢

转载自juejin.im/post/7127649327681388552