LeetCode 第 216 场周赛 题解

LeetCode 第 216 场周赛

来看配图版

题目1:5605. 检查两个字符串数组是否相等

思路:模拟

将两个数组的字符串分别按序拼接,然后比较两字符串是否相等即可。

代码:

class Solution {
public:
    bool arrayStringsAreEqual(vector& word1, vector& word2) {
        string a = "", b = "";
        for(auto w : word1) a += w;
        for(auto w : word2) b += w;
        return a == b;
    }
};

复杂度分析:

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)


题目2:5606. 具有给定数值的最小字符串

思路:模拟

题目说明了给定 n , k n, k n,k 一定能构造出字符串,所以先将所有 n n n 位都初始化为字符 a a a,一定是目前数值最小的字符串,维护一个变量 c n t cnt cnt 记录当前字符串数值,修改字符串从末尾开始增加(为了保证最小字典序),若最后一位已经修改到字符 z z z ,则倒数第二位开始增加,所以维护一个 p o s pos pos 变量记录当前需要修改的位置。直到 c n t = k cnt = k cnt=k 时结束。

代码:

class Solution {
public:
    string getSmallestString(int n, int k) {
        string res = "";
        int cnt = 0;
        for(int i = 0; i < n; i++) {
            res += "a";
            cnt++;
        }
        int pos = 1;
        while(k > cnt) {
            if(res[n - pos] == 'z') {
                pos++;
            }
            res[n - pos]++;
            k--;
        }
        return res;
    }
};

复杂度分析:

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)


题目3:5607. 生成平衡数组的方案数

思路:前缀和

由于删除一个数后,这个数后面所有数都向前挪动一位,所以原本奇数位的数变成了偶数位,偶数位的数变成了奇数位。那么对于一个删除的下标位置 i n d e x index index,删除该元素后, i n d e x index index后面所有奇数下标元素的和其实就是移除之前, i n d e x index index后面所有偶数下标元素的和。所以提前维护两个前缀和,分别记录奇数下标元素和偶数下标元素之和即可。

代码:

class Solution {
public:
    int waysToMakeFair(vector& nums) {
        int n = nums.size();
        vector odd(n + 1, 0);
        vector even(n + 1, 0);
        for(int i = 1; i <= n; i++) {
            if(i % 2 == 1) {
                odd[i] = odd[i - 1];
                even[i] = even[i - 1] + nums[i - 1];
            } else {
                odd[i] = odd[i - 1] + nums[i - 1];
                even[i] = even[i - 1];
            }
        }
        
        int cnt = 0;
        for(int i = 0; i < n; i++) {
            int o = odd[i] - odd[0] + even[n] - even[i + 1]; // 奇数下标元素之和
            int e = even[i] - even[0] + odd[n] - odd[i + 1]; // 偶数下标元素之和
            if(o == e) {
                cnt++;
            }
        }
        return cnt;
    }
};

复杂度分析:

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)


题目4:5608. 完成所有任务的最少初始能量

思路:贪心

题目要求最少初始能量,我们反向考虑这个问题,假设初始能量 z = 0 z = 0 z=0。现在我们考虑要做的第一个任务 t a s k [ i ] = [ x , y ] task[i] = [x, y] task[i]=[x,y],为了开始执行这个任务,我们需要“补”差价,也就是补上 y y y 值的能量。最终完成所有任务需要补的能量之和就是题目要求的最少初始能量。在完成这个任务后,我们还剩余能量 y − x y - x yx,此时我们需要继续去完成其他任务。当完成最后一个任务后,剩余的能量就没用了。所以,我们希望尽可能将剩余能量 y − x y - x yx 较大的任务放在前面做,这样在完成一个任务后,我们为了完成下一个任务需要补的“差价”就少,同样地,我们把剩余能量较小的任务放在后面做,这样完成最后一个任务后,我们就不会“心疼”扔掉的能量了。

当两个任务 [ x 1 , y 1 ] , [ x 2 , y 2 ] ( y 1 < y 2 ) [x_1, y_1], [x_2, y_2](y_1 < y_2) [x1,y1],[x2,y2](y1<y2)具有相同的剩余能量 r r r 时,我们优先选择做 y y y 较大的任务,这是因为,完成两个任务后,剩余能量相等,假设先做了任务1,那么下面要做任务2,需要补差价 $ y_2 - r$, 而若是先做任务2,再做任务1时需要补的差价就是 y 1 − r y_1 - r y1r,由于$ y_1 < y_2$, 故先做 y y y 较大的任务,需要补的差价就少了。

代码:

class Solution {
public:
    struct task{
        int x, y;
        task(int x, int y):x(x), y(y){}
        bool operator<(const task& a) const {
            if(a.y - a.x == y - x) { 
                // 剩余能量相同,先做y较大的任务
                return y < a.y;
            }
            // 先做剩余能量大的任务
            return y - x < a.y - a.x;
        }
    };
    
    int minimumEffort(vector>& tasks) {
        priority_queue q;
        for(auto t : tasks) {   // 放入优先队列
            task tmp(t[0], t[1]);
            q.push(tmp);
        }
        // res 记录补差价总量,也即最终要求结果
        // pos 记录当前剩余能量
        int res = 0, pos = 0;
        while(!q.empty())
        {
            task tmp = q.top();
            if(pos >= tmp.y) {	// 不用补差价
                pos -= tmp.x;
            } else {
                res += tmp.y - pos;
                pos = tmp.y - tmp.x;
            }
            q.pop();
        }
        return res;
    }
};

复杂度分析:

时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)

你可能感兴趣的:(LC周赛,Leetcode)