“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”
一、题目描述:
653. 两数之和 IV - 输入 BST
给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
示例 1:
输入: root = [5,3,6,2,4,null,7], k = 9
输出: true
示例 2:
输入: root = [5,3,6,2,4,null,7], k = 28
输出: false
二、思路分析:
- 双指针+中序遍历 对于二叉搜索树中序遍历得到的数组是升序,这样我们只需要用双指针指向一头一尾,判断是否符合target,大于则尾指针--,小于则头指针++,直到两者重合或者等于目标
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {TreeNode} root
* @param {number} k
* @return {boolean}
*/
var findTarget = function(root, k) {
const inorder=function(root){
if(root===null)return
inorder(root.left)
nodes.push(root.val)
inorder(root.right)
}
let nodes=[]
inorder(root)
let l=0,r=nodes.length-1
while(l<r){
let sum=nodes[l]+nodes[r]
if(sum===k)return true
else if(sum<k){
l++;
}else {
r--;
}
}
return false
};
- 优化:迭代+双指针+中序遍历 对于方法一,我们是先完整遍历整个二叉树,这样一定会消耗O(n)的空间,我们可以一次遍历。首先先一直遍历最左边的节点left并记录到到栈leftStack,同样一直遍历最右边节点right并记录到rightStack。这样就得到第一个方法的首位节点,这栈顶就是上一个节点,同时我们需要加入上一个节点的右/左节点,这样才能升序。
var findTarget = function(root, k) {
const getLeft = (stack) => {
const root = stack.pop();
let node = root.right;
while (node) {
stack.push(node);
node = node.left;
}
return root;
}
const getRight = (stack) => {
const root = stack.pop();
let node = root.left;
while (node) {
stack.push(node);
node = node.right;
}
return root;
};
let left = root, right = root;
const leftStack = [];
const rightStack = [];
leftStack.push(left);
while (left.left) {
leftStack.push(left.left);
left = left.left;
}
rightStack.push(right);
while (right.right) {
rightStack.push(right.right);
right = right.right;
}
while (left !== right) {
if (left.val + right.val === k) {
return true;
}
if (left.val + right.val < k) {
left = getLeft(leftStack);
} else {
right = getRight(rightStack);
}
}
return false;
}
- 深度遍历+哈希表 因为是两个节点值相加判断等于target,故我们可以先把其中一边的节点加入Set集合,这样遍历到另一个节点判断是否有target-x的值是能找到。
var findTarget = function(root, k) {
const getLeft = (stack) => {
const root = stack.pop();
let node = root.right;
while (node) {
stack.push(node);
node = node.left;
}
return root;
}
const getRight = (stack) => {
const root = stack.pop();
let node = root.left;
while (node) {
stack.push(node);
node = node.right;
}
return root;
};
let left = root, right = root;
const leftStack = [];
const rightStack = [];
leftStack.push(left);
while (left.left) {
leftStack.push(left.left);
left = left.left;
}
rightStack.push(right);
while (right.right) {
rightStack.push(right.right);
right = right.right;
}
while (left !== right) {
if (left.val + right.val === k) {
return true;
}
if (left.val + right.val < k) {
left = getLeft(leftStack);
} else {
right = getRight(rightStack);
}
}
return false;
}
4、广度遍历+哈希表 能深度遍历肯定能广度遍历
class Solution:
def findTarget(self, root: Optional[TreeNode], k: int) -> bool:
s = set()
q = deque([root])
while q:
node = q.popleft()
if k - node.val in s:
return True
s.add(node.val)
if node.left:
q.append(node.left)
if node.right:
q.append(node.right)
return False