题目
二叉搜索树中的两个节点被错误地交换;
请在不改变其结构的情况下,恢复这棵树。
案例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…
著作权归领扣网络所有。
商业转载请联系官方授权,非商业转载请注明出处。
数据结构-二叉搜索树的实现