滑动窗口练习(LeetCode)C++

1984.学生分数的最小差值

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

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

返回可能的 最小差值 。

示例 1:

输入:nums = [90], k = 1
输出:0
解释:选出 1 名学生的分数,仅有 1 种方法:
- [90] 最高分和最低分之间的差值是 90 - 90 = 0
可能的最小差值是 0

示例 2:

输入:nums = [9,4,1,7], k = 2
输出:2
解释:选出 2 名学生的分数,有 6 种方法:
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 4 = 5
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 1 = 8
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 7 = 2
- [9,4,1,7] 最高分和最低分之间的差值是 4 - 1 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 4 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 1 = 6
可能的最小差值是 2

提示:

  • 1 <= k <= nums.length <= 1000
  • 0 <= nums[i] <= 105
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int minimumDifference(vector<int>& nums, int k) {
    sort(nums.begin(), nums.end());
    int ans=100000;
    for(int i = 0; i+k-1 < nums.size();i++){
        ans=min(ans,nums[i+k-1]-nums[i]);
    }
    return ans;

}
int main(){
    vector<int>nums={9,4,1,7};
    int k=2;
    int target=minimumDifference(nums,k);
    cout<<target;
    return 0;
}

2653.滑动子数组的美丽值

给你一个长度为 n 的整数数组 nums ,请你求出每个长度为 k 的子数组的 美丽值 。

一个子数组的 美丽值 定义为:如果子数组中第 x 小整数 是 负数 ,那么美丽值为第 x 小的数,否则美丽值为 0 。

请你返回一个包含 n - k + 1 个整数的数组,依次 表示数组中从第一个下标开始,每个长度为 k 的子数组的 美丽值 。

  • 子数组指的是数组中一段连续 非空 的元素序列。

示例 1:

输入:nums = [1,-1,-3,-2,3], k = 3, x = 2
输出:[-1,-2,-2]
解释:总共有 3 个 k = 3 的子数组。
第一个子数组是 [1, -1, -3] ,第二小的数是负数 -1 。
第二个子数组是 [-1, -3, -2] ,第二小的数是负数 -2 。
第三个子数组是 [-3, -2, 3] ,第二小的数是负数 -2 。

示例 2:

输入:nums = [-1,-2,-3,-4,-5], k = 2, x = 2
输出:[-1,-2,-3,-4]
解释:总共有 4 个 k = 2 的子数组。
[-1, -2] 中第二小的数是负数 -1 。
[-2, -3] 中第二小的数是负数 -2 。
[-3, -4] 中第二小的数是负数 -3 。
[-4, -5] 中第二小的数是负数 -4 。

示例 3:

输入:nums = [-3,1,2,-3,0,-3], k = 2, x = 1
输出:[-3,0,-3,-3,-3]
解释:总共有 5 个 k = 2 的子数组。
[-3, 1] 中最小的数是负数 -3 。
[1, 2] 中最小的数不是负数,所以美丽值为 0 。
[2, -3] 中最小的数是负数 -3 。
[-3, 0] 中最小的数是负数 -3 。
[0, -3] 中最小的数是负数 -3 。

提示:

  • n == nums.length 
  • 1 <= n <= 105
  • 1 <= k <= n
  • 1 <= x <= k 
  • -50 <= nums[i] <= 50 

最初的代码是这样的:

#include <iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std; 
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
    vector<int>ans;
    for(int i = 0; i+k-1 < nums.size();i++){
        //对于窗口[i,k+i-1]排序
        vector<int>target(nums.begin() + i, nums.begin() + i + k);
        sort(target.begin(), target.end());
        if(target[x-1]<0){
             ans.push_back(target[x-1]);

        }
        else{
            ans.push_back(0);
        }
    }  
    return ans;      
}
int main(){
    vector<int>nums={-3,1,2,-3,0,-3};
    int k=2;
    int x=1;
    vector<int>target=getSubarrayBeauty(nums,k,x);
    for(int i=0;i<5;i++){
        cout<<target[i]<<endl;
    }
    return 0;
}

然而超时了。。。。

#include <iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std; 
vector<int> getSubarrayBeauty(vector<int>& nums, int k, int x) {
      const int BIAS=50;
      int cnt[BIAS*2+1]{},n=nums.size();
      //先往窗口添加k-1个数
      for(int i=0;i<k-1;i++){
        cnt[nums[i]+BIAS]++;
      }
      vector<int>ans(n-k+1);
      for(int i=k-1;i<n;i++){
        cnt[nums[i]+BIAS]++;  //进入窗口
        int left=x;
        for(int j=0;j<BIAS;j++){  //暴力枚举负数范围[-50,-1] 如果是>=0的数字,它就不会出现在这里了
            left=left-cnt[j];
            if(left<=0){ //找到美丽值
                ans[i-k+1]=j-BIAS;
                break;
            }
        }
        cnt[nums[i-k+1]+BIAS]--; //离开窗口
      }
    return ans;
}
int main(){
    vector<int>nums={-3,1,2,-3,0,-3};
    int k=2;
    int x=1;
    vector<int>target=getSubarrayBeauty(nums,k,x);
    for(int i=0;i<5;i++){
        cout<<target[i]<<endl;
    }
    return 0;
}

这是我看灵茶的思路写的,就是基于k-1个窗口,对各数字进行计数排序,然后每次向前滑动一个窗口,则 

cnt[nums[i]+BIAS]++;//进入
{。。。}
 cnt[nums[i-k+1]+BIAS]--; //离开窗口

那么对于求第x小的数,则暴力枚举【-50,-1】的数字的个数,当x减去这么多数字的频率之后,此时的数字则为所求结果,但是如果该x小的数不在这个范围内,则为0即可。

1493.删掉一个元素以后全为1的最长数组

给你一个二进制数组 nums ,你需要从中删掉一个元素。

请你在删掉元素的结果数组中,返回最长的且只包含 1 的非空子数组的长度。

如果不存在这样的子数组,请返回 0 。

提示 1:

输入:nums = [1,1,0,1]
输出:3
解释:删掉位置 2 的数后,[1,1,1] 包含 3 个 1 。

示例 2:

输入:nums = [0,1,1,1,0,1,1,0,1]
输出:5
解释:删掉位置 4 的数字后,[0,1,1,1,1,1,0,1] 的最长全 1 子数组为 [1,1,1,1,1] 。

示例 3:

输入:nums = [1,1,1]
输出:2
解释:你必须要删除一个元素。

提示:

  • 1 <= nums.length <= 105
  • nums[i] 要么是 0 要么是 1 。
#include<iostream>
#include<vector>
using namespace std;
int longestSubarray(vector<int>& nums) {
    int n=nums.size();
    vector<int>pre(n),suf(n);
    pre[0]=nums[0];
    for(int i=1;i<n;i++){
        pre[i]=nums[i]?pre[i-1]+1:0;
    }
    suf[n-1]=nums[n-1];
    for(int i=n-2;i>=0;i--){
        suf[i]=nums[i]?suf[i+1]+1:0;
    }
    int ans=0;
    for(int i=0;i<n;i++){
        int preSum= i==0?0:pre[i-1];
        int sufSum= i==n-1?0:suf[i+1];
        ans=max(ans,sufSum+preSum);
    }
    return ans;
}
int main(){
    vector<int>nums={1,1,0,1};
    int tar=longestSubarray(nums);
    cout<<tar;
    return 0;
}

  • 11
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值