六月集训(06)滑动窗口

1.LeetCode:1984. 学生分数的最小差值

原题链接


        给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。

        从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。

        返回可能的 最小差值 。

        示例 1:

        输入:nums = [90], k = 1

        输出:0

        示例 2:

        输入:nums = [9,4,1,7], k = 2

        输出:2

        提示:

        1 <= k <= nums.length <= 1000

        0 <= nums[i] <= 105


        先对数组排序然后开始滑动k个长度的窗口并维护最大差值。

class Solution {
public:
    int minimumDifference(vector<int>& nums, int k) {
        if(k==1)
        return 0;
        int ans=INT_MAX;
        sort(nums.begin(),nums.end());
        int n=nums.size();
        for(int i=0;i<=n-k;i++)
        ans=min(ans,nums[i+k-1]-nums[i]);
        return ans;
    }
};

2.LeetCode:1763. 最长的美好子字符串

原题链接


        当一个字符串 s 包含的每一种字母的大写和小写形式 同时 出现在 s 中,就称这个字符串 s 是 美好 字符串。比方说,“abABB” 是美好字符串,因为 ‘A’ 和 ‘a’ 同时出现了,且 ‘B’ 和 ‘b’ 也同时出现了。然而,“abA” 不是美好字符串因为 ‘b’ 出现了,而 ‘B’ 没有出现。

        给你一个字符串 s ,请你返回 s 最长的 美好子字符串 。如果有多个答案,请你返回 最早 出现的一个。如果不存在美好子字符串,请你返回一个空字符串。

        示例 1:

        输入:s = “YazaAay”

        输出:“aAa”

        示例 2:

        输入:s = “Bb”

        输出:“Bb”

        示例 3:

        输入:s = “c”

        输出:“”

        示例 4:

        输入:s = “dDzeE”

        输出:“dD”

        提示:

        1 <= s.length <= 100

        s 只包含大写和小写英文字母。


        同样,对于每个位置 i 我们枚举所有长度,并维护最长长度。

char * longestNiceSubstring(char * s)
{
    int ipos=0,maxlen=0,up=0,low=0;
    for(int i=0;i<strlen(s);i++)
    {
        low=0;
        up=0;
        for(int j=i;j<strlen(s);j++)
        {
            if(islower(s[j]))
            low|=1<<(s[j]-'a');
            else 
            up|=1<<(s[j]-'A');
            if(low==up&&maxlen<j-i+1)
            {
                maxlen=j-i+1;
                ipos=i;
            }
        }
    }
    char *res=(char *)malloc(sizeof(char)*(maxlen+1));
    strncpy(res,s+ipos,maxlen);
    res[maxlen]='\0';
    return res;
}

3.LeetCode:2269. 找到一个数字的 K 美丽值

原题链接


        一个整数 num 的 k 美丽值定义为 num 中符合以下条件的 子字符串 数目:

        子字符串长度为 k 。

        子字符串能整除 num 。

        给你整数 num 和 k ,请你返回 num 的 k 美丽值。

        注意:

        允许有 前缀 0 。

        0 不能整除任何值。

        一个 子字符串 是一个字符串里的连续一段字符序列。

        示例 1:

        输入:num = 240, k = 2

        输出:2

        示例 2:

        输入:num = 430043, k = 2

        输出:2

        提示:

        1 <= num <= 10^9

        1 <= k <= num.length (将 num 视为字符串)


        这里吧数字转换为字符串数组更好操作,这里依次选取吧num转换为字符串后的每个k长度的连续子数组不断检验合法性即可。

class Solution {
public:
    int divisorSubstrings(int num, int k) {
        string tmp=to_string(num);
        int ans=0;
        for(int i=0;i+k<=tmp.size();++i){
            int sum=stoi(tmp.substr(i,k));
            if(sum&&num%sum==0){
                ans++;
            }
        }
        return ans;
    }
};

4.LeetCode:995. K 连续位的最小翻转次数

原题链接


        给定一个二进制数组 nums 和一个整数 k 。

        k位翻转 就是从 nums 中选择一个长度为 k 的 子数组 ,同时把子数组中的每一个 0 都改成 1 ,把子数组中的每一个 1 都改成 0 。

        返回数组中不存在 0 所需的最小 k位翻转 次数。如果不可能,则返回 -1 。
子数组 是数组的 连续 部分。

        示例 1:

        输入:nums = [0,1,0], K = 1

        输出:2

        示例 2:

        输入:nums = [1,1,0], K = 2

        输出:-1

        示例 3:

        输入:nums = [0,0,0,1,0,1,1,0], K = 3

        输出:3

        提示:

        1 <= nums.length <= 10^5

        1<= k <= nums.length


        这道题很容易想到不断遍历数组,然后每次遇到0就对他后面k个位置进行翻转。但是这样复杂度就是O(N*K)了一定会T的。现在我们的这个思路不变,来对翻转进行优化。

        现在来思考,某个位置的被翻转的情况都被前K-1个位置影响,而这种情况有两种,一是他被翻转了偶数次,但他是0,另一种是他被翻转了奇数次,但他是1.(这两种都代表他现在是0,同时注意到,被反转的情况是 i 在原数组中的值和被反转次数同奇偶)。

        那么有没有一种方法记录某个位置在我们遍历的途中被反转的次数。答案是有的,我们利用一个队列来进行记录,他的长度代表着 i 位置被反转的次数。每次遍历前先把不属于[k,i]这个区间的元素出队,然后检查 i 位置是否需要翻转,如果需要翻转就把他入队代表把从i开始的k个数字进行翻转,同时如果长度越界的话要返回-1.

class Solution {
public:
    int minKBitFlips(vector<int>& nums, int k) {
        int n=nums.size(),ans=0;
        queue<int> q;
        for(int i=0;i<n;++i){
            while(!q.empty()&&q.front()+k<=i){
                q.pop();
            }
            if(nums[i]==(q.size()&1)){
                if(i+k>n){
                    return -1;
                }
                q.push(i);
                ans++;
            }
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值