LeetCode——第十八天(统计「优美子数组」)

LeetCode——第十八天
1248. 统计「优美子数组」

给你一个整数数组 nums 和一个整数 k。

如果某个 连续 子数组中恰好有 k 个奇数数字,我们就认为这个子数组是「优美子数组」。

请返回这个数组中「优美子数组」的数目。

示例 1:

输入:nums = [1,1,2,1,1], k = 3
输出:2
解释:包含 3 个奇数的子数组是 [1,1,2,1] 和 [1,2,1,1] 。

示例 2:

输入:nums = [2,4,6], k = 1
输出:0
解释:数列中不包含任何奇数,所以不存在优美子数组。

示例 3:

输入:nums = [2,2,2,1,2,2,1,2,2,2], k = 2
输出:16

提示:

1 <= nums.length <= 50000
1 <= nums[i] <= 10^5
1 <= k <= nums.length

分析:一次循环遍历,求出每个最优子数组,再去判断一个个遍历显然是会超时。这边自己想到就是找个k个奇数,然后判断前后偶数的个数,相乘就是这一个区间的最优子数组个数,不断遍历到结束,不过写起来比较繁琐一点,官方给出了增加一个数组来存放奇数下标,就不需求另外用四个变量去存放修改位置了。

odd数组代码

class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int n = (int)nums.size();
        int odd[n+2], res = 0, count = 0;//odd用于存放出现奇数的下标,count计数
        //遍历存放下标
        for(int i=0;i<n;i++){
            if(nums[i]%2) odd[++count] = i;
        }
        //首尾即边界情况处理
        odd[0] = -1;
        odd[++count] = n;
        for(int i=1;i+k<=count;i++){//这里是遍历odd数组,从1开始
            res+=(odd[i]-odd[i-1])*(odd[i+k]-odd[i+k-1]);
            //第一次出现奇数和上一次之间以及第k+1个奇数到第k个奇数之间分别有多少个偶数
            //例如题目11211,假设k是3,那么上面就是odd[1]-odd[0]=0-(-1)=1
            //后面是odd[i+k]-odd[i+k-1],就是odd[4]-odd[3]=4-3=1,结果是1*1=1
        }
        return res;
    }
};

官方第二个前缀和太秀了,具体备注写了些,写的有点乱,下面是官网说明。
另外前缀和+差分具体可以看看这两篇博客(第一篇有解释点,第二篇偏代码和应用):
前缀和差分
前缀和、二维前缀和与差分的小总结

在这里插入图片描述

前缀和代码

class Solution {
public:
    int numberOfSubarrays(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> cnt(n+1,0);//cnt用于存放某个奇数个数出现的次数
        int odd = 0, res = 0;//odd存储奇数下标
        cnt[0] = 1;
        for(int i=0;i<n;i++){
            odd+=nums[i]&1;
            /*
            如果是奇数则个数加1,否则不变,可以用if加%方式来判断
            这边是按位与运算,偶数最后一位肯定是0
            */
            res+=odd>=k?cnt[odd-k]:0;
            cnt[odd]+=1;
            /*
            先说cnt,比如题目11211,i到3时候,此时对应odd为1,2,3
            对应就是cnt[1]=1,cnt[2]=2,cnt[3]=1,即出现奇数次数为1的情况有1次
            这边2出现两次,因为1121,在2这里又出现一次,这样就可以统计出所以奇数出现次数的情况
            */
        }
        return res;
    }
};
2.总结

这题目第一种应该很多都知道,就是边界情况要处理,第二种反正我不是很会。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值