二叉搜索树节点最小距离(题号783)
题目
给你一个二叉搜索树的根节点 root
,返回 树中任意两不同节点值之间的最小差值 。
注意:本题与 530:leetcode-cn.com/problems/mi… 相同
示例 1:
输入:root = [4,2,6,1,3]
输出:1
示例 2:
输入:root = [1,0,48,null,null,12,49]
输出:1
提示:
- 树中节点数目在范围
[2, 100]
内 0 <= Node.val <= 105
链接
解释
这题啊,这题是根本没想道点子上。
首先看题目,是一个二叉搜索树,只要我们拿到二叉搜索树所有节点的值,之后进行排序,最后循环数组,取其相邻的两个数的差,即可得出最小值。
重点就是在怎么取所有节点的值,笔者想的很简单,不管用什么遍历方法,拿到所有节点值之后排序一下就行了,其实不然。
由于是二叉搜索树,那么只要进行中序遍历的话,拿到的结果就是按照从小到大的顺序进行排列的,此时在进行差值比较即可。
原来这题考的是中序遍历,那说到中序遍历,这题就简单了。
自己的答案(暴力解法)
var minDiffInBST = function(root) {
var arr = [root]
nums = []
min = Number.MAX_SAFE_INTEGER
while (arr.length) {
var item = arr.shift()
nums.push(item.val)
item.left && arr.push(item.left)
item.right && arr.push(item.right)
}
nums.sort((a, b) => a- b)
for (let i = nums.length - 1; i > 0; i--) {
min = Math.min(nums[i] - nums[i - 1], min)
}
return min
};
这里随便遍历了一下,拿到了所有二叉树的值,之后排序,排序之后再循环就可以拿到最小差值了。
完全没有想到重点。
更好的方法(中序-遍历)
既然是中序遍历,首先说说遍历方法👇:
var minDiffInBST = function(root) {
var stack = []
prv = Number.MIN_SAFE_INTEGER
min = Number.MAX_SAFE_INTEGER
while (root || stack.length) {
while (root) {
stack.push(root)
root = root.left
}
root = stack.pop()
min = Math.min(root.val - prv, min)
prv = root.val
root = root.right
}
return min
};
遍历的代码十分简单,首先需要有个stack
来存储root
数组,之后开始进行遍历操作。
首先开始外层遍历,在外层遍历中,第一步要做的就是内层遍历。
如果root
存在,那么对root
进行解析操作。在内层遍历中,首先将root
推入stack
中,之后取到root
的左子树,然后再将root
的左子树推入到到stack
中,以此类推,直到root
为null
。
对root
处理完成后即可开始外层循环的真正内容,先将root
赋值为stack
的最后一个元素,此时root
的val
就是遍历中应该取的值,所以在此时进行比较和赋值。
完事了再将root
赋值为它的右子树,完成一轮遍历。
然后就完事了,这样遍历的结果就是中序遍历了,相对比较简单,如果不理解背下来就好,代码量也不多。
更好的方法(中序-递归)
递归的方法比遍历更容易理解,而且感觉上更简单一些👇:
var minDiffInBST = function(root) {
var prv = Number.MIN_SAFE_INTEGER
min = Number.MAX_SAFE_INTEGER
function inorder(root) {
if (!root) return
inorder(root.left)
min = Math.min(root.val - prv, min)
prv = root.val
inorder(root.right)
}
inorder(root)
return min
};
prv
和min
就不说了,针对这题的特殊变量。
递归的中序遍历首先是一个函数,这里叫inorder
。函数内部首先判断root
是否存在,如果不存在,直接返回;如果存在,先执行对其左子树进行递归操作——inorder(root.left)
,之后对root
的val
进行处理和比较;完事了再进行root
右子树的递归操作,就好了。
其逻辑真的十分简单,对每个节点都进行递归操作,如果有左子树先执行左子树,之后执行当前节点,最后执行右子树,简直不要太简单。
更好的方法(中序-Morris)
这个方法就有点绕了,笔者是真的看不懂,后来在同事的解释下才勉强理解,前前后后花了快4个小时,这里就放下官方的答案吧,后续会单独出一篇文章来讲解Morris遍历的。
官方地址:leetcode-cn.com/problems/bi…
PS:想查看往期文章和题目可以点击下面的链接:
这里是按照日期分类的👇
经过有些朋友的提醒,感觉也应该按照题型分类
这里是按照题型分类的👇
有兴趣的也可以看看我的个人主页👇