算法—leetcode—99

139 阅读2分钟

题目

二叉搜索树中的两个节点被错误地交换;
请在不改变其结构的情况下,恢复这棵树。

案例1

输入:[1,3,null,null,2]
{"Val":1,"Left":{"Val":3,"Right":{"Val":2}},}

输出:[3,1,null,null,2] 
{{"Val":3,"Left":{"Val":1,"Right":{"Val":2}},}}

案例2

输入:[3,1,4,null,null,2]
{"Val":3,"Left":{"Val":1},"Right":{"Val":4,Left:{Val:2}}}

输出:[2,1,4,null,null,3] 
{"Val":2,"Left":{"Val":1},"Right":{"Val":4,Left:{Val:3}}}

定义

二叉搜索树(二叉排序树或二叉查找树)

特点

  • 非空左子数的所有键值小于根节点的键值
  • 非空右子数的所有键值大于根节点的键值
  • 左右子数均为二叉搜索树
  • 树中没有键值相等的节点

思路

中序遍历:左中右 根据二叉搜索树特点(正常二叉搜索树中序遍历的结果递增的顺序)

找到二叉搜索树中序遍历得到值序列的不满足条件的位置。
如果有一个,我们记为i,那么对应被错误交换的节点即为ai对应的节点和ai+1​对应的节点,我们分别记为x和y。
交换x和y两个节点即可

方案一

  • 1.中序遍历二叉树结果存储到数组中
  • 2.在数组中查找顺序被交换的两个元素
  • 3.遍历二叉树查找元素相等的值进行交叉替换
package leetcode

import(
	"log"
)

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

// recoverTree
// 恢复一个二叉搜索树
func recoverTree(root *TreeNode)  {
	// 定义一个数组保存中序遍历结果
    nums := []int{}
    
    // 定义一个中序遍历函数,将结果保存到数组中
    var inorder func(node *TreeNode)
    inorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        inorder(node.Left)
        nums = append(nums, node.Val)
        inorder(node.Right)
    }
    // 中序遍历二叉树
    inorder(root)
    log.Println(nums)
    // 查找交换的节点
    x, y := findTwoSwapped(nums)
    // TODO 如果都是-1 则代表已经是二叉搜索树 1237564
    log.Println(x, y)
    recover(root, 2, x, y)
}

// 1237564
// findTwoSwapped
// 找到两个交换的索引位置值
func findTwoSwapped(nums []int) (int, int) {
	// 用于存储错误交换的位置
    x, y := -1, -1
    for i := 0; i < len(nums) - 1; i++ {
		// TODO 两个错误的位置一定是相连的吗?
		// 当后一个小于前一个的时候进行存储
        if nums[i + 1] < nums[i] {
			// 为什么y可以进行替换?找到最终的错的位置
            y = nums[i+1]
            if x == -1 {
                x = nums[i]
            } else {
                break
            }
        }
    }
    return x, y
}

方案二

  • 1.额外定义三个节点类型变量,pre用于表示前缀节点,x/y用于存储异常节点
  • 2.中序遍历二叉树当前节点值与前缀节点值进行对别
  • 3.如果x/y不位空代表存在异常节点,则进行恢复
// 恢复二叉搜索树
// recover
// @param root 二叉树
func recover(root *TreeNode, count, x, y 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
        }
    }
    recover(root.Left, count, x, y)
    recover(root.Right, count, x, y)
}

// recoverTreeV2
// 恢复一个二叉搜索树 通过节点指针保存
func recoverTreeV2(root *TreeNode)  {
	var x, y, pre  *TreeNode
    
    // 定义一个中序遍历函数,将结果保存到数组中
    var inorder func(node *TreeNode)
    inorder = func(node *TreeNode) {
        if node == nil {
            return
        }
        log.Println("node", node.Val)
        inorder(node.Left)
        if pre==nil {
			pre = node
			log.Println(pre.Val)
		} else {
			if pre.Val > node.Val {
				y = node
				if x==nil {
					x = pre
				}
			}
			// 保存当前节点作为上一个节点
			pre = node
		}
        inorder(node.Right)
    }
    // 中序遍历二叉树
    inorder(root)
    if x!= nil && y != nil{
		recover(root, 2, x.Val, y.Val)
	}
}

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/re…
著作权归领扣网络所有。
商业转载请联系官方授权,非商业转载请注明出处。
数据结构-二叉搜索树的实现