第 359 场 LeetCode 周赛题解

A 判别首字母缩略词

第 359 场 LeetCode 周赛题解_第1张图片

签到题…

class Solution {
public:
    bool isAcronym(vector<string> &words, string s) {
        string pf;
        for (auto &s: words)
            pf.push_back(s[0]);
        return pf == s;
    }
};

B k-avoiding 数组的最小总和

第 359 场 LeetCode 周赛题解_第2张图片

贪心:从 1 1 1开始升序枚举,判断当前数是否可以放入数组,同时维护当前数组中的数,直到找到 n n n个数。

class Solution {
public:
    int minimumSum(int n, int k) {
        set<int> vis;
        int s = 0;
        for (int i = 1; vis.size() < n; i++) {
            if (vis.count(k - i))
                continue;
            vis.insert(i);
            s += i;
        }
        return s;
    }
};

C 销售利润最大化

第 359 场 LeetCode 周赛题解_第3张图片
第 359 场 LeetCode 周赛题解_第4张图片

动态规划+树状数组:首先将 o f f e r s offers offers s t a r t i start_i starti升序排序,枚举 o f f e r s offers offers中的元素,设 p [ i ] p[i] p[i]为销售的最右区间的右端点为 i i i的情况下能够得到的最大利润,设当前元素为 [ l , r , g ] [l, r, g] [l,r,g],则可以更新状态: p [ r ] = m a x { p [ r ] m a x { p [ k ]    ∣    0 ≤ k ≤ l − 1 } + g p[r]=max\left\{\begin{matrix} p[r] \\ max\{p[k] \;|\; 0\le k \le l-1 \} + g \end{matrix}\right. p[r]=max{p[r]max{p[k]0kl1}+g
利用树状数组来维护前缀上的极大值。

class Solution {
public:

    int maximizeTheProfit(int n, vector<vector<int>> &offers) {
        N = n + 5;
        a = vector<int>(N, 0);
        sort(offers.begin(), offers.end());
        int res = 0;
        for (auto &it: offers) {
            int l = it[0] + 1, r = it[1] + 1, g = it[2];//树状数组中下标从1开始
            int cur = query(l - 1) + g;//查询前缀极大值
            res = max(res, cur);
            update(r, cur); //树状数组更新
        }
        return res;
    }

    int N;
    vector<int> a;//树状数组

    inline int lowbit(int x) {
        return x & -x;
    }

    void update(int loc, int val) {// li[loc]=max(li[loc], val);
        for (; loc < N; loc += lowbit(loc))
            a[loc] = max(a[loc], val);
    }

    int query(int loc) {// max{li[k] | 1<=k<=loc}
        int res = 0;
        for (; loc > 0; loc -= lowbit(loc))
            res = max(res, a[loc]);
        return res;
    }
};

D 找出最长等值子数组

第 359 场 LeetCode 周赛题解_第5张图片

二分+哈希:用二分查找答案 l e n len len,这样问题就变成了:判断从 n u m s nums nums 中删除最多 k k k 个元素后,是否存在长为 l e n len len 的等值子数组。设 l o c [ v ] loc[v] loc[v] n u m s nums nums中所有 v v v所在下标组成的升序数组,若存在 0 ≤ i ≤ i + l e n − 1 < l o c [ v ] . s i z e ( ) 0\le i \le i+len-1 < loc[v].size() 0ii+len1<loc[v].size() 使得 l o c [ v ] [ i + l e n − 1 ] − l o c [ v ] [ i ] + 1 − l e n ≤ k loc[v][i + len - 1] - loc[v][i] + 1 - len \le k loc[v][i+len1]loc[v][i]+1lenk,则说明可以得到长为 l e n len len 的值为 v v v的等值子数组,枚举 n u m s nums nums中不同的数,即可判断是否可以得到长为 l e n len len 的等值子数组。

class Solution {
public:
    int longestEqualSubarray(vector<int> &nums, int k) {
        int n = nums.size(), l = 1, r = n;
        unordered_map<int, vector<int>> loc;
        for (int i = 0; i < n; i++)
            loc[nums[i]].push_back(i);
        auto can = [&](int len) {//判断是否可以得到长为len的等值子数组
            int find = 0;
            for (auto &[_, vec]: loc) {//枚举不同的数
                for (int i = 0; i + len - 1 < vec.size(); i++)
                    if (vec[i + len - 1] - vec[i] + 1 - len <= k)
                        return true;
            }
            return false;
        };
        while (l < r) {//二分查找答案
            int mid = (l + r + 1) / 2;
            if (can(mid))
                l = mid;
            else
                r = mid - 1;
        }
        return l;
    }
};

你可能感兴趣的:(LeetCode,leetcode,算法,贪心算法,动态规划,树状数组,二分查找,哈希)