LeetCode-2379. 得到 K 个黑块的最少涂色次数-1652. 拆炸弹-1052. 爱生气的书店老板-2841. 几乎唯一子数组的最大和-2461. 长度为 K 子数组中最大和

2379. 得到 K 个黑块的最少涂色次数

思路:维护一个长度为k的滑动窗口,并用一个使用一个unorder_map映射记录在该窗中中‘W’和'B'的个数。那么,要保证有一个长度为k的全为‘B’的字符串,就只需要把对应map中,键‘W’全改为‘B’即可。也就是说对于当前窗口,要实现全为‘B’的字符串,需要操作的次数就是键‘W’对应的值。基于这个思想,让窗口依次向下滑动即可。

#include<iostream>
#include<vector>
#include<cstdlib>
#include<unordered_map>
using namespace std;
class Solution {
public:
    int minimumRecolors(string blocks, int k) {
        unordered_map<char,int> mp;
        int size = blocks.size();
        // 记录第一个窗口的对应映射
        for(int i=0;i<k;i++){
            mp[blocks[i]]++;
        }
        int tempOp=mp['W'],minOp = mp['W'];
        for(int i=1;i<size-k+1;i++){
            mp[blocks[i-1]]--;
            mp[blocks[i+k-1]]++;
            tempOp=mp['W'];
            minOp = min(minOp,tempOp);
        }
        return minOp;
    }
};

1052. 爱生气的书店老板

思路:本题困于如何实现循环数组,使用了取模的方式。但是官方题解给出了一种更好的方式来求解,即将原来的code数组,扩容成原来的两倍,并且将code数组原来的数据直接赋值给后面一半,这样当访问数组第i+k个元素时,就不存在越界问题了。之后的操作就是普通的滑动窗口了。

class Solution {
public:
    vector<int> decrypt(vector<int>& code, int k) {
        int n = code.size();
        vector<int> res(n);
        if (k == 0) {
            return res;
        }
        code.resize(n * 2);
        copy(code.begin(), code.begin() + n, code.begin() + n);
        int l = k > 0 ? 1 : n + k;
        int r = k > 0 ? k : n - 1;
        int w = 0;
        for (int i = l; i <= r; i++) {
            w += code[i];
        }
        for (int i = 0; i < n; i++) {
            res[i] = w;
            w -= code[l];
            w += code[r + 1];
            l++;
            r++;
        }
        return res;
    }
};

1052. 爱生气的书店老板

思路:先计算出所有时间下不生气的人数总和,再利用滑动窗口不断向后滑动,处理再当前窗口内老板生气的情况下忍住的所有不生气人数。

#include <iostream>
#include <vector>
#include <cstdlib>
#include <map>
using namespace std;

class Solution {
public:
    int maxSatisfied(vector<int>& customers, vector<int>& grumpy, int minutes) {
        int totalSatisfied = 0;
        int maxAdditionalSatisfied = 0;
        int currentAdditionalSatisfied = 0;
        int size = customers.size();

        // 计算在不生气的情况下的总满意顾客数
        for (int i = 0; i < size; i++) {
            if (grumpy[i] == 0) {
                totalSatisfied += customers[i];
            }
        }

        // 计算前 'minutes' 分钟内的额外满意顾客数
        for (int i = 0; i < minutes; i++) {
            if (grumpy[i] == 1) {
                currentAdditionalSatisfied += customers[i];
            }
        }

        maxAdditionalSatisfied = currentAdditionalSatisfied;

        // 使用滑动窗口计算其他时间段的额外满意顾客数
        for (int i = minutes; i < size; i++) {
            if (grumpy[i] == 1) {
                currentAdditionalSatisfied += customers[i]; // 新加入的
            }
            if (grumpy[i - minutes] == 1) {
                currentAdditionalSatisfied -= customers[i - minutes]; // 移除的
            }
            maxAdditionalSatisfied = max(maxAdditionalSatisfied, currentAdditionalSatisfied);
        }

        return totalSatisfied + maxAdditionalSatisfied; // 返回总满意顾客数
    }
};

2841. 几乎唯一子数组的最大和

思路:基本上就是简单的滑动窗口,只是要记录一个map映射,用来保存当前窗口内有多少对不同的map映射,用来和m进行比较,只有当map映射数满足大于等于m时,采取尝试更新最终的maxSum。这道题两个注意点(我自己的错误),第一,map映射的值在为0时,并不会主动删去,所以要手动使用erase方法;第二,对于求和变量curSum和maxSum最好要开long long。

#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
    long long maxSum(vector<int>& nums, int m, int k) {
        unordered_map<int,int> mp;
        int size = nums.size();
        if(m>size) return 0;
        long long curSum=0,maxSum=0;
        for(int i=0;i<k;i++){
            mp[nums[i]]++;
            curSum+= nums[i];
        }
        if(mp.size()>=m) maxSum=curSum;
        for(int i=1;i<size-k+1;i++){
            mp[nums[i-1]]--;
            if(mp[nums[i-1]]==0) mp.erase(nums[i-1]);
            mp[nums[i-1+k]]++;
            curSum = curSum-nums[i-1]+nums[i-1+k];
            if(mp.size()>=m) maxSum = max(maxSum,curSum);
        }
        return maxSum;
    }
};

2461. 长度为 K 子数组中的最大和

思路:与上一题几乎完全一致,只是一个是小于m,一个是等于k,不赘述。

class Solution {
public:
    long long maximumSubarraySum(vector<int>& nums, int k) {
        unordered_map<int,int> mp;
        int size = nums.size();
        if(k>size) return 0;
        long long curSum=0,maxSum=0;
        for(int i=0;i<k;i++){
            mp[nums[i]]++;
            curSum += nums[i];
        }
        if(mp.size()==k) maxSum=curSum;
        for(int i=1;i<size-k+1;i++){
            mp[nums[i-1]]--;
            if(mp[nums[i-1]]==0) mp.erase(nums[i-1]);
            mp[nums[i-1+k]]++;
            curSum = curSum-nums[i-1]+nums[i-1+k];
            if(mp.size()==k) maxSum = max(maxSum,curSum);
        }
        return maxSum;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值