剑指offer专项突击版第19天

剑指 Offer II 056. 二叉搜索树中两个节点之和
中序遍历+双指针
bst中序就是升序序列,然后双指针即可

class Solution {
public:
    void get_nums(TreeNode* root, vector<TreeNode*> &nums){
        if(!root) return;
        get_nums(root->left, nums);
        nums.emplace_back(root);
        get_nums(root->right, nums);

    }
    bool findTarget(TreeNode* root, int k) {
        vector<TreeNode*> nums;
        get_nums(root,nums);
        for(int i = 0, j = nums.size()-1; i < nums.size(); i++) {
            while(j > i && nums[i]->val + nums[j]->val > k) j--;
            if(j > i && nums[i]->val+nums[j]->val == k) return true;
        }
        return false;
    }
};

dfs+哈希表
因为两个结点是相互的,所以不用担心还未遍历整个树就开始判断。

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

剑指 Offer II 058. 日程表

直接遍历导致时间复杂度为 O ( N 2 ) O(N^2) O(N2)

class MyCalendar {
public:
    vector<pair<int,int>> ls;
    MyCalendar() {
        
    }

    bool book(int start, int end) {
        for(auto range: ls) {
            if(range.first < end && start < range.second)
                return false;
        }
        ls.push_back({start,end});
        return true;
    }
};

线段树优化

class MyCalendar {
    unordered_set<int> tree, lazy;

public:
    bool query(int start, int end, int l, int r, int idx) {
        if (r < start || end < l) {
            return false;
        }
        /* 如果该区间已被预订,则直接返回 */
        if (lazy.count(idx)) {
            return true;
        }
        if (start <= l && r <= end) {
            return tree.count(idx);
        }
        int mid = (l + r) >> 1;
        return query(start, end, l, mid, 2 * idx) ||
               query(start, end, mid + 1, r, 2 * idx + 1);
    }

    void update(int start, int end, int l, int r, int idx) {
        if (r < start || end < l) {
            return;
        }
        if (start <= l && r <= end) {
            tree.emplace(idx);
            lazy.emplace(idx);
        } else {
            int mid = (l + r) >> 1;
            update(start, end, l, mid, 2 * idx);
            update(start, end, mid + 1, r, 2 * idx + 1);
            tree.emplace(idx);
            if (lazy.count(2 * idx) && lazy.count(2 * idx + 1)) {
                lazy.emplace(idx);
            }
        }
    }

    bool book(int start, int end) {
        if (query(start, end - 1, 0, 1e9, 1)) {
            return false;
        }
        update(start, end - 1, 0, 1e9, 1);
        return true;
    }
};

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/fi9suh/solution/ri-cheng-biao-by-leetcode-solution-w06j/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

剑指 Offer II 057. 值和下标之差都在给定的范围内

滑动窗口+二分查找

  • 由于下标差不能超过 k k k ,所以使用滑动窗口来限制窗口内元素个数为 k + 1 k+1 k+1 个。
  • 其次要满足滑动窗口内存在两元素差值小于等于 t t t ,假设当前的元素为 x x x ,那么就只需要在窗口内找到一个数在 [ x − t , x + t ] [x-t, x+t] [xt,x+t] 范围内。
  • x x x 右边的元素就不管了?只要右边的元素会跟 x x x 在同个窗口那么它就会考虑到 x x x ,而不用 x x x 来考虑。
  • 由于序列是无序的,如果直接找需要 O ( n k ) O(nk) O(nk) 会TLE,这里就需要只用set来动态维护序列有序性,并且二分快速找到大于等于 x − t x-t xt 的数集中最小的元素,然后判断这个元素是否<= x + t x+t x+t
class Solution {
public:
    bool containsNearbyAlmostDuplicate(vector<int>& nums, int k, int t) {
        set<int> st;
        for(int i = 0; i < nums.size(); i++) {
            auto it = st.lower_bound(max(nums[i],INT_MIN+t) - t); //防止key溢出int
            if(it != st.end() && *it <= min(nums[i],INT_MAX-t) + t) {//防止key溢出int
                return true;
            }
            st.insert(nums[i]);
            if(i >= k) st.erase(nums[i-k]); //滑动窗口
        }
        return false;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值