两数之和 IV - 输入 BST

引言

这个和之前两数之和问题相差不大,区别在于数据结构的不同,之前第一题那个存储数据用的是数组,这里用的是BST树

原题

给定一个二叉搜索树 root 和一个目标结果 k,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
两数之和 IV - 输入 BST

BST 树

BST 树的主要特点就是节点的大小大于它左孩子的大小,小于它右孩子的大小

做法

我的做法参考题解

哈希 + dfs

先用哈希表把数字存起来,然后再遍历 BST树 。思路比较简单,就是直接哈希+遍历。感觉没有用到BST树得特性

class Solution {
private:
    unordered_set<int>map;
public:
    bool findTarget(TreeNode* root, int k) {
        if(root==nullptr)return false;
        if(map.count(k-root->val)){
            return true;
        }
        map.insert(root->val);
        return findTarget(root->left,k)||findTarget(root->right,k);
    }
};

哈希+bfs

这个和上面的dfs方法类似,自不必多说。但是bfs运行起来时间和空间都比dfs要少

class Solution {
public:
    bool findTarget(TreeNode* root, int k) {
        unordered_set<int>map;
        queue<TreeNode*>que;
        que.push(root);
        while(!que.empty()){
            TreeNode* current = que.front();
            que.pop();
            if(map.count(k-current->val)){
                return true;
            }
            map.insert(current->val);
            if(current->left!=nullptr){
                que.push(current->left);
            }
            if(current->right != nullptr){
                que.push(current->right);
            }
        }
        return false;
    }
};

dfs排序,双向列表

因为bfs的特性, 可以用中序遍历将它转换为一个有序数组。 然后就直接用两个指针left、right双向遍历

class Solution {
private:
    vector<int>list;
public:
    void inorderTraversal(TreeNode* root){
        if(root == nullptr) return;
        inorderTraversal(root->left);
        list.push_back(root->val);
        inorderTraversal(root->right);
    }
    bool findTarget(TreeNode* root, int k) {
        inorderTraversal(root);
        int left= 0;
        int right = list.size() - 1;
        int sum = 0;
        while(left<right){
            sum = list[left] + list[right];
            if(sum == k) return true;
            if(sum<k) left++;
            else right--;
        }
        return false;
    }
};

迭代 + 双向列表

这个方法思想也和上面那个差不多,只不过将递归转为了迭代。并且用到了stack这个数据结构。有一说一,要理解起来还真不容易。
讲一下步骤:

  1. 从root开始,将它所有的左节点压入leftStack栈中,将它的所有右节点压入rightStack中,这时候栈的头部都是值最小或者最大的指针
  2. 然后开始遍历
  3. 如果结果刚好满足,则return true; 如果小于,则调用getLeft函数,弹出并且返回栈中的下一个元素,往往比前面的元素要大,同时将该指针的right指针的所有左节点都压入栈中
class Solution {
private:
    stack<TreeNode*> leftStack;
    stack<TreeNode*> rightStack;
    TreeNode* getLeft(){
        TreeNode* root = leftStack.top();
        leftStack.pop();
        TreeNode* node = root ->right;
        while(node!=nullptr){
            leftStack.push(node);
            node = node->left;
        }
        return root;
    }
    TreeNode* getRight(){
        TreeNode* root = rightStack.top();
        rightStack.pop();
        TreeNode* node = root ->left;
        while(node!=nullptr){
            rightStack.push(node);
            node = node->right;
        }
        return root;
    }
public:
    bool findTarget(TreeNode* root, int k) {
        TreeNode* leftNode = root; 
        TreeNode* rightNode = root;
        while(leftNode->left!=nullptr){
            leftStack.push(leftNode);
            leftNode = leftNode -> left;
        }
        leftStack.push(leftNode);
        while(rightNode->right!=nullptr){
            rightStack.push(rightNode);
            rightNode = rightNode->right;
        }
        rightStack.push(rightNode);
        while(leftNode != rightNode){
            cout<<leftNode->val<<" "<<rightNode->val<<endl;
            if(leftNode->val + rightNode->val == k) return true;
            if(leftNode->val + rightNode->val < k ){
                //if(!leftStack.size())return false;
                leftNode = getLeft();
            }
            else {
                //if(!rightStack.size())return false;
                rightNode = getRight(); 
            }
        }
        return false;
    }
};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值