在问 · 算法题解

653. 两数之和 IV - 输入二叉搜索树

简单二叉树深度优先搜索 + 哈希集合力扣原题 ↗

题目描述

输入一棵二叉搜索树的根节点 root(用层序数组表示)和一个整数 k。

判断树中能否找到两个不同的节点,使它们的值相加正好等于 k。能找到返回 true,否则返回 false。

示例 1
输入:root = [5,3,6,2,4,null,7], k = 9
输出:true

解释:例如 3 + 6 = 9,或 2 + 7 = 9。

示例 2
输入:root = [5,3,6,2,4,null,7], k = 28
输出:false

解释:树中任意两值之和都达不到 28。

数据范围

  • 节点数在 [1, 10^4] 范围内。
  • -10^4 <= Node.val <= 10^4
  • 保证 root 是一棵合法的二叉搜索树。
  • -10^5 <= k <= 10^5

解题思路:深度优先搜索 + 哈希集合

和「两数之和」一样用哈希集合:遍历树的每个节点,先查 k - node.val 是否已在集合中,在就找到一对;不在就把 node.val 放进集合,继续遍历左右子树。先查后放保证不会把同一个节点用两次。(也可以利用 BST 中序有序,对中序数组用双指针。)

为什么正确

访问一个节点时,seen 中恰好是先于它被访问的全部节点值;若存在一对答案,当后访问的那个节点被检查时一定能发现。

复杂度分析

时间 O(n),每个节点最多访问一次,哈希查询 O(1);空间 O(n)。

易错点

要先查再放:如果先把 node.val 放进集合再查,k = 2·node.val 时会把同一个节点配对两次(例如 root=[1],k=2 应返回 false)。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def findTarget(self, root: Optional[TreeNode], k: int) -> bool:
        seen = set()
        def dfs(node):
            if not node:
                return False
            if k - node.val in seen:
                return True
            seen.add(node.val)
            return dfs(node.left) or dfs(node.right)
        return dfs(root)

载入编辑器,自己跑一遍 →

其他解法

哈希集合解法对任意二叉树都成立;中序遍历 + 双指针专门利用二叉搜索树有序,把问题归结为有序数组上的两数之和。

解法 2:中序遍历 + 双指针 时间 O(n),空间 O(n)

二叉搜索树的中序遍历是升序序列。先中序遍历得到有序数组,再用左右双指针找和为 k 的两个数。和小于 k 就右移左指针,大于 k 就左移右指针。

用上了二叉搜索树的有序性,不需要哈希。代价是必须先完整遍历一遍,不能像哈希集合那样找到就提前结束。

class Solution:
    def findTarget(self, root: Optional[TreeNode], k: int) -> bool:
        vals = []

        def inorder(node):
            if not node:
                return
            inorder(node.left)
            vals.append(node.val)
            inorder(node.right)

        inorder(root)
        i, j = 0, len(vals) - 1
        while i < j:
            s = vals[i] + vals[j]
            if s == k:
                return True
            if s < k:
                i += 1
            else:
                j -= 1
        return False

二叉树 专题的其他题目

查看 二叉树 全部题目 →