此题同 783. 二叉搜索树节点最小距离
https://leetcode-cn.com/problems/minimum-absolute-difference-in-bst/
力扣重复的题越来越多了
使用额外空间迭代
输入是二叉排序树,按照中序遍历可以得到这棵树的结点值,此时用双指针的思想遍历结点值即可得到最小值
想要找到升序数组中的最大差值,最简单的想法就是二重循环遍历,但是这样做没有利用到升序的性质
利用i和j两个指针作为标记,对于d = abs(L[i]-L[j])
,存在三种情况
- d<minn
- d=minn
- d>minn
对于1
和2
,此时i,j的差值小于等于minn,表示至少找到了一组不大于minn的组合,此时j如果往后移动,则一定会大于minn,如果i往后移动,则有可能会小于minn —— i往后移动
对于3
,此时i和j的距离过大,i应该往后移动 —— i往后移动
发现这三种情况都对应着i往后移动,那么j何时移动?
在升序数组中,除非两个指针相遇,否则j不应该主动移动,因为j移动就是相当于增加i与j之间的距离,所以只有当i、j相遇的时候,j才需要往后移动
```python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
# input : 二叉搜索树
# 获取升序排列的值
L = []
self.helper(root,L)
# 双指针开始遍历
i,j=0,1
minn=abs(L[1]-L[0])
size = len(L)
while i<size and j<size:
# 避免计算相同节点,j往后移动
if i==j:
j+=1
continue
# 更新minn
if abs(L[j]-L[i]) < minn:
minn=abs(L[j]-L[i])
i+=1 # 总是尝试移动i
return minn
def helper(self,root,L):
if root:
self.helper(root.left,L)
L.append(root.val)
self.helper(root.right,L)
按照分析写出代码后发现,i与j的距离总是不会大于1,相当于i、j不断取两两相接的数进行差值判断,所以上面的while循环可以改为
while i<size and j<size:
# 更新minn
if abs(L[j]-L[i]) < minn:
minn=abs(L[j]-L[i])
i+=1
j+=1
其实这个规律表示,在有序数组里面,最小的差值一定来自相接的两两元素之间
当然这个two point的遍历只有在数组有序的情况下可以使用,如果无序情况下最好的做法还是排序然后再使用two point
代码的时间复杂度为 O ( N ) O(N) O(N),空间复杂度为 O ( N ) O(N) O(N)
直接递归
在得出的最小的差值一定来自相接的两两元素之间结论后,可以想到,如果在递归过程中,保存当前结点的前驱,那么就可以得到与上一个结点的差值
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def getMinimumDifference(self, root: TreeNode) -> int:
# python中常量不可变,需要维护全局变量
self.minn = abs(root.val - (root.left.val if root.left else root.right.val))
self.pre = None
self.helper(root)
return self.minn
def helper(self,root):
if root:
self.helper(root.left)
if self.pre:
self.minn=min(self.minn,abs(self.pre.val-root.val))
self.pre=root
self.helper(root.right)
遍历依然采用中序遍历,需要注意的是pre和minn必须存储成类内成员变量,而不是作为参数传递进去