题目来自LeetCode,链接:two-sum-iv。具体描述为:
给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
示例1:
输入:
5
/ \
3 6
/ \ \
2 4 7
Target = 9
输出: True
示例2:
输入:
5
/ \
3 6
/ \ \
2 4 7
Target = 28
输出: False
这跟前面的两数之和以及两数之和II-输入有序数组很相似,不过输入的是BST。
同样可以用两数之和的方法去做(直接用一个set保存target-当前数),需要遍历一次BST,每遍历一个节点就判断是否出现在set之中了,是的话返回True,否则将target-当前值加入set。
或者可以模仿有序数组的方法,先中序遍历BST得到升序数组,然后直接用双指针方法也可以解决此问题。
实际提交发现前面两种方法时间上并不是很有优势,所以想了想,其实在用前面第二种方法的时候,可以不用得到一个升序数组再用双指针的,完全可以在遍历过程中就用双指针的。为了实现这一点,可以参考栈形式的中序遍历:
- 当前节点初始化为root,将其所有左节点(包括左节点的左节点,一直到叶子节点为止)和所有右节点分别入栈到左节点栈和右节点栈,可以得到left为最左节点,对应最小值,right为最右节点,对应最大值
- 计算left和right对应节点值之和,与target对比
- 相等,直接返回True
- 小于,需要增大left,判断left的右节点是否存在
- 存在,则将left的右节点的所有左节点入栈,left=此右节点的最左节点(也可以说是栈顶节点,不过为了简便可以在代码中省去出栈操作)
- 不存在,直接left=栈顶出栈节点,也就是当前left的父节点
- 大于,需要减少right,判断right的左节点是否存在
- 存在,则将right的左节点的所有右左节点入栈,right=此左节点的最右节点
- 不存在,直接right=栈顶出栈节点,也就是当前right的父节点
本质上,上面的算法就是升序数组方法在BST中的实现,换了个数据结构罢了。
另外,需要注意到的是以上所有方法的时间和空间复杂度均为。
JAVA版代码如下:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
private TreeNode pushLeft(TreeNode leftNode, Stack<TreeNode> leftNodeStack) {
while (leftNode.left != null) {
leftNodeStack.push(leftNode);
leftNode = leftNode.left;
}
return leftNode;
}
private TreeNode pushRight(TreeNode rightNode, Stack<TreeNode> rightNodeStack) {
while (rightNode.right != null) {
rightNodeStack.push(rightNode);
rightNode = rightNode.right;
}
return rightNode;
}
public boolean findTarget(TreeNode root, int k) {
Stack<TreeNode> leftNodeStack = new Stack<>();
Stack<TreeNode> rightNodeStack = new Stack<>();
TreeNode leftNode = pushLeft(root, leftNodeStack);
TreeNode rightNode = pushRight(root, rightNodeStack);
int sum2num = 0;
while (leftNode != rightNode) {
sum2num = leftNode.val + rightNode.val;
if (sum2num == k) {
return true;
}
else if (sum2num < k) {
if (leftNode.right != null) {
leftNode = pushLeft(leftNode.right, leftNodeStack);
}
else {
leftNode = leftNodeStack.pop();
}
}
else {
if (rightNode.left != null) {
rightNode = pushRight(rightNode.left, rightNodeStack);
}
else {
rightNode = rightNodeStack.pop();
}
}
}
return false;
}
}
提交结果如下:
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 pushLeft(self, leftNode, leftNodeStack):
while leftNode.left is not None: #将所有左节点入栈
leftNodeStack.append(leftNode)
leftNode = leftNode.left
return leftNode
def pushRight(self, rightNode, rightNodeStack):
while rightNode.right is not None: #将所有右节点入栈
rightNodeStack.append(rightNode)
rightNode = rightNode.right
return rightNode
def findTarget(self, root: TreeNode, k: int) -> bool:
leftNodeStack, rightNodeStack = [], []
leftNode = self.pushLeft(root, leftNodeStack)
rightNode = self.pushRight(root, rightNodeStack)
while leftNode is not rightNode:
sum2num = leftNode.val + rightNode.val
if sum2num == k: #找到符合条件的两个节点
return True
elif sum2num < k: #两数之和小于target,需要增大左节点
if leftNode.right is not None: #当前节点右节点不为空的情况将其左节点全部入栈
leftNode = self.pushLeft(leftNode.right, leftNodeStack)
else: #当前节点右节点为空的情况弹出当前节点的父节点
leftNode = leftNodeStack.pop()
else: #两数之和大于target,需要减小右节点
if rightNode.left is not None: #当前节点左节点不为空的情况将其右节点全部入栈
rightNode = self.pushRight(rightNode.left, rightNodeStack)
else: #当前节点左节点为空的情况弹出当前节点的父节点
rightNode = rightNodeStack.pop()
return False
提交结果如下:
来源:CSDN
作者:JR_Chan
链接:https://blog.csdn.net/JR_Chan/article/details/104593534