每日一题打卡:1248. 统计「优美子数组」

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-number-of-nice-subarrays
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目描述:

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

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

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

 

示例 1:

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

暴力搜索法:(超时了)

class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        int sum = 0;
        int count;
        for(int i=0;i<nums.length;i++){
            count = 0;
            for(int j=i;j<nums.length;j++)
            {
                if(nums[j]%2==1)count++;
                if(count==k)sum++;         
            }
        }
        return sum;
    }
}

双指针:(时间复杂度O(n))

 /*
    (双指针) 
    双指针扫描 r 在前,l 在后。
    如果当前位置是奇数,则更新计数器,如果当前 [l, r] 有了恰好 k 个奇数,则移动 l 直到不满足,期间统计出长度为 tot。
    让 ans 累加 tot。
    如果当前位置是偶数,则说明贡献的答案和上一次是奇数的时候一样,直接让 ans 累加上一次的 tot。

    时间复杂度
    每个位置最多遍历两次,故时间复杂度为 O(n)。

    空间复杂度
    仅需要常数的额外空间。
     */
    public int numberOfSubarrays(int[] nums, int k) {
        int n = nums.length;

        int cnt = 0, tot = 0, ans = 0;
        for (int r = 0, l = 0; r < n; r++) {
            if (isOdd(nums[r])) {
                cnt++;
                if (cnt == k) tot = 0;

                while (cnt == k) {
                    tot++;
                    if (isOdd(nums[l]))
                        cnt--;
                    l++;
                }
                ans += tot;
            } else{
                ans += tot;
            }
        }

        return ans;
    }

    private boolean isOdd(int n) {
        return n % 2 == 1;
    }

前缀和+hashmap

class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        // sum是前缀和
        int sum=0; 
        int res=0;
        // map的键是前缀和  map的值是前缀和出现的次数 
        HashMap<Integer,Integer> map=new HashMap<>();
        // 前缀和为0 出现的次数是1次
        map.put(0,1); 
        for(int num:nums){
            sum+=(num&1);
            /*当前前缀和是sum,尝试在map中查找 是否存在键值是sum-k(即前缀和是sum-k) ,若找到,即找到子序列和是k*/
            if(map.containsKey(sum-k)){
                res+=map.get(sum-k);
            }
            map.put(sum,map.getOrDefault(sum,0)+1);
        }
        return res;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值