1. 程式人生 > 其它 >LeetCode第 74 場雙週賽題解

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];
    }
};