优美子数组

本文介绍了一种算法,用于计算给定数组中奇数元素个数为特定值的子数组数量。通过遍历数组并使用标记记录奇数位置,算法能够高效地找到符合条件的所有子数组。

在这里插入图片描述

go版本

func numberOfSubarrays(nums []int, k int) int {
    arr := make([]int,0)
    flag ,res := 0, 0


    for i := 0; i <len(nums); i++ {
        flag++

        if(nums[i] % 2 == 1){
            arr = append(arr, flag)
            flag = 0
        }

        if(len(arr) >= k){
            res += arr[len(arr)-k]
        }
    }
    return res
}

php版本

func numberOfSubarrays(nums []int, k int) int {
    arr := make([]int,0)
    flag ,res := 0, 0


    for i := 0; i <len(nums); i++ {
        flag++

        if(nums[i] % 2 == 1){
            arr = append(arr, flag)
            flag = 0
        }

        if(len(arr) >= k){
            res += arr[len(arr)-k]
        }
    }
    return res
}
以下是解决「统计优美子数组」问题的完整代码和详细解释。 --- ### 解决方案 我们可以通过前缀和与哈希表的结合来高效地解决问题。以下是实现代码: ```python def TEST_DO_NOT_CHANGE(nums, k): # 初始化结果变量 rlt = 0 ##########start下面可以改动 # 将奇数标记为1,偶数标记为0 prefix_sum = [0] * (len(nums) + 1) for i in range(len(nums)): prefix_sum[i + 1] = prefix_sum[i] + (nums[i] % 2) # 使用哈希表记录前缀和出现的次数 count_map = {} count_map[0] = 1 # 初始状态:前缀和为0的情况出现一次 for i in range(1, len(prefix_sum)): current_sum = prefix_sum[i] target = current_sum - k if target in count_map: rlt += count_map[target] # 更新当前前缀和的计数 if current_sum in count_map: count_map[current_sum] += 1 else: count_map[current_sum] = 1 ##########end 上面可以改动 return rlt if __name__ == "__main__": print(TEST_DO_NOT_CHANGE([1, 1, 2, 1, 1], 3)) # 输出: 2 print(TEST_DO_NOT_CHANGE([2, 4, 6], 1)) # 输出: 0 print(TEST_DO_NOT_CHANGE([2, 2, 2, 1, 2, 2, 1, 2, 2, 2], 2)) # 输出: 16 ``` --- ### 给出解释 #### 1. 问题分析 我们需要找到数组中所有包含 **恰好 `k` 个奇数** 的连续子数组的数量。直接枚举所有子数组的时间复杂度为 \(O(n^2)\),对于较大的输入会非常低效。因此,我们需要优化算法。 #### 2. 核心思想:前缀和 + 哈希表 - **前缀和**:我们可以将数组中的奇数标记为 `1`,偶数标记为 `0`,这样问题就转化为寻找前缀和之差等于 `k` 的子数组。 - **哈希表**:使用哈希表记录每个前缀和出现的次数,从而快速计算满足条件的子数组数量。 #### 3. 步骤详解 1. **构建前缀和数组**: - 将原数组中的奇数替换为 `1`,偶数替换为 `0`。 - 构建前缀和数组 `prefix_sum`,其中 `prefix_sum[i]` 表示从数组开头到第 `i-1` 个元素的奇数个数。 2. **初始化哈希表**: - 创建一个字典 `count_map`,用于记录每个前缀和出现的次数。 - 初始时,前缀和为 `0` 的情况出现一次(即空数组)。 3. **遍历前缀和数组**: - 对于每个位置 `i`,计算当前前缀和 `current_sum`。 - 计算目标值 `target = current_sum - k`,表示我们需要找到的前缀和。 - 如果 `target` 存在于 `count_map` 中,则说明存在若干个子数组满足条件,累加其出现次数。 - 更新当前前缀和的计数到 `count_map` 中。 4. **返回结果**: - 最终,变量 `rlt` 中存储的就是满足条件的子数组数量。 #### 4. 示例运行 ##### 示例 1: 输入:`nums = [1, 1, 2, 1, 1], k = 3` - 替换后的数组为 `[1, 1, 0, 1, 1]`。 - 前缀和数组为 `[0, 1, 2, 2, 3, 4]`。 - 满足条件的子数组为 `[1, 1, 2, 1]` 和 `[1, 2, 1, 1]`,总数为 `2`。 ##### 示例 2: 输入:`nums = [2, 4, 6], k = 1` - 替换后的数组为 `[0, 0, 0]`。 - 前缀和数组为 `[0, 0, 0, 0]`。 - 没有满足条件的子数组,总数为 `0`。 ##### 示例 3: 输入:`nums = [2, 2, 2, 1, 2, 2, 1, 2, 2, 2], k = 2` - 替换后的数组为 `[0, 0, 0, 1, 0, 0, 1, 0, 0, 0]`。 - 前缀和数组为 `[0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 2]`。 - 满足条件的子数组总数为 `16`。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值