算法练习Day5 [LeetCode]1248.优美子数组

[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

  1. 考虑暴力枚举法解题
    考虑nums所有的子数组,检查每个子数组中奇数元素的个数,统计优美子数组的个数。因为双重循环求子数组,所以时间复杂度为O(n^2),再加上后面要遍历子数组求其中的奇数个数,时间复杂度为O(n),所有总的时间复杂度为O(n ^3),不符合题意。
    题目中要求时间复杂度为O(n)

这里要引入一个概念,如何判断题目的时间复杂度呢?
最简单、快捷的方式就是通过观察题目中的数据范围来确定。
数据范围与算法大致时间复杂度的对应表如下:
在这里插入图片描述
本题的数据范围到达了 50000,因此我们将时间复杂度划定在 O(n)的范围内。
根据官方的题解我们可以用数学方法考虑这道题

2.数学方法

class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] odd = new int[n + 2];
        //建立一个odd 数组来记录第 i 个奇数的下标
        //此处数组开头和结尾预设了数组,做边界处理
        int ans = 0, cnt = 0;//优美子数组个数和odd数组的下标
        for (int i = 0; i < n; ++i) {
            if ((nums[i] & 1) != 0) {
            //奇偶判断,奇数二进制最后一位必为1,和1进行与运算后结果必为1,偶数为0
                odd[++cnt] = i;
            }
        }
        odd[0] = -1;//左边界处理
        odd[++cnt] = n;//右边界处理
        for (int i = 1; i + k <= cnt; ++i) {
            ans += (odd[i] - odd[i - 1]) * (odd[i + k] - odd[i + k - 1]); //计算优美子数组总数
        }
        return ans;
    }
}

复杂度分析

时间复杂度:O(n),其中 n为数组的大小。遍历 odd 数组最坏情况下需要 O(n) 的时间。

空间复杂度:O(n),其中 n为数组的大小。odd 数组需要 O(n)的空间。

  1. 前缀和、差分方法求解
class Solution {
    public int numberOfSubarrays(int[] nums, int k) {
        int n = nums.length;
        int[] cnt = new int[n + 1];
        int odd = 0, ans = 0;
        cnt[0] = 1;
        for (int i = 0; i < n; ++i) {
            odd += nums[i] & 1;
            ans += odd >= k ? cnt[odd - k] : 0;
            cnt[odd] += 1;
        }
        return ans;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值