Java&C++题解与拓展——leetcode653.两数之和IV - 输入BST【emplace,ArrayDeque学习与使用】

这篇博客主要介绍了如何在二叉搜索树中寻找两个节点,使得它们的值之和等于给定的目标数。首先介绍了使用深度优先搜索(DFS)的方法,利用哈希集合存储已遍历过的节点值,如果找到目标值则返回true。然后,讲解了利用中序遍历和双指针的优化方案,通过两个栈分别保存左子树和右子树的节点,从最小和最大的节点开始查找,根据目标和调整指针方向。两种方法的时间复杂度均为O(n),空间复杂度也为O(n)。
摘要由CSDN通过智能技术生成
每日一题做题记录,参考官方和三叶的题解

题目要求

在这里插入图片描述

思路一:DFS

用DFS遍历整棵树,并用哈希表set存储遍历过的值,查找set是否有与当前值相加得到目标的值。
两种语言的哈希表分别为HashSet和unordered_Set,在19日的题目中也有使用。

Java

class Solution {
    Set<Integer> set = new HashSet<>();
    public boolean findTarget(TreeNode root, int k) {
        if(root == null)
            return false;
        if(set.contains(k - root.val))
            return true;
        set.add(root.val);
        return findTarget(root.left, k) | findTarget(root.right, k);
    }
}
  • 时间复杂度: O ( n ) O(n) O(n) n n n为BST的大小
  • 空间复杂度: O ( n ) O(n) O(n)

C++

class Solution {
public:
    unordered_set<int> set;
    bool findTarget(TreeNode* root, int k) {
        if(root == nullptr)
            return false;
        if(set.count(k - root -> val))
            return true;
        set.emplace(root -> val);
        return findTarget(root -> left, k) || findTarget(root -> right, k);
    }
};
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

emplace与insert

  • 学习参考链接
  • c++ 11中的多数容器都增加了一个新的插入元素函数方法emplace,简单来说它具有较高的效率,可以替代大部分的insert操作,原理在于其无需临时变量和隐式转换。

思路二:中序遍历+双指针

利用一下BST中序输出有序的特征,然后用双指针移动查找。
利用两个栈存放符合当前条件的较小值和较大值,栈顶元素分别是符合当前条件的最小值和最大值,也即BST中的“最”左值和“最”右值。

Java

class Solution {
    public boolean findTarget(TreeNode root, int k) {
        Deque<TreeNode> ls = new ArrayDeque<>(), rs = new ArrayDeque<>();//定义两个栈
        TreeNode tmp = root;
        //分别存放根左和根右
        while(tmp != null) {
            ls.addLast(tmp);
            tmp = tmp.left;
        }
        tmp = root;
        while(tmp != null) {
            rs.addLast(tmp);
            tmp = tmp.right;
        }
        //从最左(小)和最右(大)开始查找
        TreeNode l = ls.peekLast(), r = rs.peekLast();
        while(l.val < r.val) {
            int t = l.val + r.val;
            if(t == k)
                return true;
            else if(t < k) //小则向右找
                l = getNext(ls, true);
            else //大则向左找
                r = getNext(rs, false);    
        }
        return false;
    }

    TreeNode getNext(Deque<TreeNode> s, boolean isLeft) {
        TreeNode cur = s.pollLast();
        //找比cur大or小一点的值
        //找比cur右or左一点的值
        TreeNode node = isLeft ? cur.right : cur.left;
        while(node != null) {
            s.addLast(node);
            node = isLeft ? node.left : node.right;
        }
        return s.peekLast();
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

ArrayDeque

  • 学习参考链接
  • 简介
    • 一个两端皆可插入/删除的队列
    • 简单区别一下peek和poll
方法功能
addLast(key)将key加入队尾
peekLast(key)返回队尾元素key ,不删除

C++

注意指针地址符不要少,写java写习惯了导致调了好久。

class Solution {
public:
    bool findTarget(TreeNode* root, int k) {
        stack<TreeNode *> ls, rs; //定义两个栈
        TreeNode *tmp = root;
        //分别存放根左和根右
        while(tmp != nullptr) {
            ls.push(tmp);
            tmp = tmp->left;
        }
        tmp = root;
        while(tmp != nullptr) {
            rs.push(tmp);
            tmp = tmp->right;
        }
        //从最左(小)和最右(大)开始查找
        TreeNode *l = ls.top(), *r = rs.top();
        while(l->val < r->val) {
            int t = l->val + r->val;
            if(t == k)
                return true;
            else if(t < k) //小则向右找
                l = getNext(ls, true);
            else //大则向左找
                r = getNext(rs, false);
        }
        return false;
    }
    TreeNode *getNext(stack<TreeNode *> &s, bool isLeft) {
        TreeNode *cur = s.top();
        s.pop();
        //找比cur大or小一点的值
        //找比cur右or左一点的值
        TreeNode *node = isLeft ? cur->right : cur->left;
        while(node != nullptr) {
            s.push(node);
            node = isLeft ? node->left : node->right;
        }
        return s.top();
    }
};
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( n ) O(n) O(n)

总结

本题属于简单“树”类题目,直接套用DFS即可解决(BFS也一样),但是要想到如何利用二叉搜索树的特点并不简单,法二的思路值得多多琢磨。


欢迎指正与讨论!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值
>