返回顶部

LeetCode第 74 场双周赛题解

6020. 将数组划分成相等数对

题目描述:给你一个长度为2n的数组nums,将其分为n组,每组含有两个相等的元素,问是否可行

思路:根据题意模拟即可

时间复杂度:\(O(n)\)

参考代码:

class Solution {
public:
    bool divideArray(vector<int>& nums) {
        vector<int>a(501 , 0);
        for(auto& num : nums) a[num]++;
        for(auto& num : a) if(num % 2 == 1) return false;
        return true;
    }
};

6021. 字符串中最多数目的子字符串

题目描述:给定字符串s,再给定一个长度为2的字符串t,可以在s中插入t中的一个字符,问插入字符后的字符串s含有多少子序列与t相同。

思路:显然最大值再t[0]放在s的前面和将t[1]放在s的后面这两种情况中取得,对于每一种情况,稍微模拟一下即可求出含有多少子序列与t相等,注意t[0] = t[1]时要特判一下。

时间复杂度:\(O(n)\)

参考代码:

class Solution {
public:
    long long maximumSubsequenceCount(string text, string pattern) {
        auto solve = [&](string s){
            long long res = 0;
            int cnt0 = 0 , cnt1 = 0;
            for(auto& c : s){
                if(c != pattern[0] && c != pattern[1]) continue;
                if(c == pattern[0]){
                    ++cnt0;
                    if(pattern[0] == pattern[1]) res += cnt0 - 1;
                }
                else{
                    ++cnt1;
                    res += cnt0;
                }
            }
            return res;
        };
        return max(solve(pattern[0] + text) , solve(text + pattern[1]));
    }
};

6022. 将数组和减半的最少操作次数

题目描述:给你一个正整数数组 nums 。每一次操作中,你可以从 nums 中选择 任意 一个数并将它减小到 恰好 一半。(注意,在后续操作中你可以对减半过的数继续执行操作)请你返回将 nums 数组和 至少 减少一半的 最少 操作数。

思路:比较明显的贪心,每次选择最大的数减半即可。使用优先队列维护数组中的最大值。

时间复杂度:\(O(nlogn)\)

参考代码:

class Solution {
public:
    int halveArray(vector<int>& nums) {
        double sum = 0;
        priority_queue<double>heap;
        for(auto& num : nums){
            sum += num;
            heap.push(num);
        }
        int res = 0;
        double cur = 0;
        sum /= 2;
        while(cur < sum){
            double num = heap.top();
            heap.pop();
            cur += num / 2;
            heap.push(num / 2);
            ++res;
        }
        return res;
    }
};

6023. 用地毯覆盖后的最少白色砖块

题目描述:给你一个下标从 0 开始的 二进制 字符串floor ,它表示地板上砖块的颜色。

floor[i] = '0' 表示地板上第 i块砖块的颜色是 黑色 。
floor[i] = '1' 表示地板上第 i块砖块的颜色是 白色 。
同时给你 numCarpetscarpetLen 。你有 numCarpets 条黑色的地毯,每一条 黑色 的地毯长度都为 carpetLen 块砖块。请你使用这些地毯去覆盖砖块,使得未被覆盖的剩余 白色 砖块的数目 最小 。地毯相互之间可以覆盖。请你返回没被覆盖的白色砖块的 最少 数目。

思路:比较明显的dp。定义状态\(f_{i , j}\)表示使用\(i\)块地毯对于前\(j\)个字符且第\(i\)块地毯的右边恰好放在\(j\)位置时能够覆盖的最大白色的数量。显然当地毯总长度大于字符串长度时有转移方程:

\[f_{i , j} = \sum_{k = 1}^{j} a_k \;i * carpetLen \geq j , a_k = (s_{k - 1} \neq 0) \]

\(a_k\)可以使用前缀和预处理出,故可以\(O(1)\)转移。下使用的\(a_i\)表示的就是前\(i\)个字符的前缀和。

当地毯总长度小于字符串长度时,有:

\[f_{i , j} = \mathop{max}\limits_{k = 0}^{j - carpetLen}f_{i - 1 , k} + a_j - a_{j - carpetLen} \]

最终答案为原字符串中1的个数减去\(f_{numCarpets , n}\)

时间复杂度:\(O(n^2)\)

参考代码:

class Solution {
public:
    int minimumWhiteTiles(string floor, int m, int len) {
        int n = floor.size();
        vector<int>a(n + 1 , 0);
        for(int i = 1 ; i <= n ; ++i) a[i] = floor[i - 1] == '1', a[i] += a[i - 1];
        vector<vector<int>>f(m + 1 , vector<int>(n + 1 , 0));
        int res = 0;
        for(int i = 1 ; i <= m ; ++i){
            for(int j = 1 ; j <= n ; ++j){
                if(i * len >= j) f[i][j] = a[j];
                else f[i][j] =  f[i - 1][j - len] + a[j] - a[j - len];
                f[i][j] = max(f[i][j] , f[i][j - 1]);
            }
        }
        return a[n] - f[m][n];
    }
};
posted @ 2022-03-20 12:27  cherish-lgb  阅读(24)  评论(0编辑  收藏  举报