leetcode竞赛:310 场周赛

日期:20220911
链接:https://leetcode.cn/contest/weekly-contest-310/

题目一:6176. 出现最频繁的偶数元素

次数相等时选最小的数。因为这个WA一次

class Solution {
public:
    int mostFrequentEven(vector<int>& nums) {
        unordered_map<int, int> ct;
        int ret = -1, m = 0;
        for (auto c: nums) {
            if (c % 2) continue;
            ct[c]++;
            if (ct[c] > m) {
                m = ct[c];
                ret = c;
            } else if (ct[c] == m && c < ret) {
                ret = c;
            }
        }
        return ret;
    }
};

题目二: 6177. 子字符串的最优划分

直接贪心就行。

class Solution {
public:
    int partitionString(string s) {
        unordered_map<char, int> dict;
        int cnt = 0;
        for (int i = 0, j = 0; i <= s.size(); i++) {
            char c = s[i];
            if (dict[c] > 0) {
                cnt++;
                dict.clear();
            }
            dict[c]++;
        }
        return cnt + 1;
    }
};

看到一个大神的答案。可以用bitset来做。
第二次写,双指针更熟练了。

class Solution {
public:
    int partitionString(string s) {
        int n = s.size(), cnt = 0;
        vector<int> wd(26);
        for (int i = 0, j = 0; i < n; i = j) {
            while (j < n && wd[s[j] - 'a'] == 0) {
                wd[s[j++] - 'a']++;
            }
            cnt++;
            for (int i = 0; i < 26; i++) wd[i] = 0;
        }
        return cnt;
    }
};

题目三: 6178. 将区间分为最少组数

这题,没做出来。。。很郁闷。想着是贪心,按顺序排序后,一遍一遍的尽可能多的把所有不重叠的区间选完。
但是33个样例,是重复的得用multiset的过。换成multiset后,34个又不过。
看答案是用区间覆盖来做。某个区间最多被覆盖多少次,就需要分多少组。所以通过差分数组,可以统计每一个区间中的数字被覆盖了多少次。

class Solution {
public:
    int minGroups(vector<vector<int>>& intervals) {
        int n = intervals.size();
        vector<int> diff(1000005);
        for (auto &vc : intervals) {
            diff[vc[0]]++;
            diff[vc[1] + 1]--;
        }
        int res = diff.front();
        for (int i = 1; i <= 1000000; i++) {
            diff[i] += diff[i - 1];
            res = max(res, diff[i]);
        }
        return res;
    }
};

第二次实现,开始还是超时了。快速敏锐的想到用 multiset 来做,然后通过了。还是第一种差分的方式好,但是难想。
事实上,完全可以用优先队列来做,因为优先队列也允许重复。

class Solution {
public:
    int minGroups(vector<vector<int>>& intervals) {
        int n = intervals.size(), cnt = 0;
        sort(intervals.begin(), intervals.end());
        multiset<int> sset;
        for (auto &p : intervals) {
            if (sset.empty() || *sset.begin() >= p[0]) {
                sset.insert(p[1]);
            } else {
                int x = *sset.begin();
                sset.erase(sset.begin());
                sset.insert(p[1]);
            }
        }

        return sset.size();
    }
};
// 优先队列版
class Solution {
public:
    int minGroups(vector<vector<int>>& intervals) {
        int n = intervals.size(), cnt = 0;
        sort(intervals.begin(), intervals.end());
        priority_queue<int, vector<int>, greater<int>> que;
        for (auto &p : intervals) {
            if (que.empty() || que.top() >= p[0]) {
                que.push(p[1]);
            } else {
                int x = que.top();
                que.pop();
                que.push(p[1]);
            }
        }

        return que.size();
    }
};

这里开了一个100w大小的数组,MB级别的。

题目四:6206. 最长递增子序列 II

典型的动态规划。 f ( i ) f(i) f(i) 表示,以索引 i i i 结尾的子序列,最长是多少。对于 f ( i ) f(i) f(i) ,我们要找到 j j j,满足 j < i j < i j<i,并且
n u m s [ i ] − k ≤ n u m s [ j ] < n u m s [ i ] nums[i] - k \le nums[j] < nums[i] nums[i]knums[j]<nums[i]
的最大的 f [ j ] f[j] f[j]。如果这样做,每次转移需要遍历 [ 0 , i ) [0, i) [0,i) 就是 O ( n 2 ) O(n^2) O(n2) 的复杂度,肯定过不了。
可以转化思维:找索引 j j j 我求不了,干脆我直接求 n u m s [ j ] nums[j] nums[j] 值得范围得了。直接找 [ n u m s [ i ] − k , n u m s [ i ] − 1 ] [nums[i] - k, nums[i] - 1] [nums[i]k,nums[i]1] 这个区间的最大值。反正 nums[i] 的范围只有 10w。线段树搞定。
最近整理了线段树模板:

class SegmentTree {
public:
    void init() {
        _build_tree(1, 0, _n);
    }
    SegmentTree(int n) : _n(n), tree((n + 2) << 2) { }

    void modify(int idx, int val) {
        _modify(1, 0, _n, idx, val);
    }
    int query(int L, int R) {
        return _query(1, 0, _n, L, R);
    }
private:
    void _build_tree(int root, int L, int R) {
        if (L == R) {
            // tree[root].max_num = arr[l];
            return;
        }
        int mid = (L + R) >> 1;
        _build_tree(root * 2, L, mid);
        _build_tree(root * 2 + 1, mid + 1, R);
        _update(root);
        return ;
    }
    void _modify(int root, int rl, int rr, int idx, int val) {
        if (rl == rr) {
            tree[root] = val;
            return;
        }
        int mid = (rl + rr) >> 1;
        if (idx <= mid) {
            _modify(root << 1, rl, mid, idx, val);
        } else {
            _modify(root << 1 | 1, mid + 1, rr, idx, val);
        }
        _update(root);
        return ;
    }

    int _query(int root, int rl, int rr, int L, int R) {

        if (rl >= L && rr <= R) {
            return tree[root];
        }
        int ans = INT_MIN;
        int mid = (rl + rr) >> 1;
        if (mid >= L) {
            ans = max(ans, _query(root << 1, rl, mid, L, R));
        }
        if (mid < R) {
            ans = max(ans, _query(root << 1 | 1, mid + 1, rr, L, R));
        }
        return ans;
    }
    void _update(int root) {
        tree[root] = max(tree[root << 1], tree[root << 1 | 1]);
        return;
    }
    // default [0, n] root is 1;
    int _n;
    vector<int> tree;
};

class Solution {
public:
    int lengthOfLIS(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> f(n);
        int res = 1;
        SegmentTree sg(100000);
        sg.init();
        for (int i = 0; i < n; i++) {
            int l = max(0, nums[i] - k), r = nums[i] - 1;
            f[i] = sg.query(l, r) + 1;
            sg.modify(nums[i], f[i]);
            res = max(res, f[i]);
        }
        return res;
    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值