LeetCode 1524. 和为奇数的子数组数目

好的!让我们详细解释 LeetCode 1524. 和为奇数的子数组数目 这道题的思路和解法。

题目 : https://leetcode.cn/problems/number-of-sub-arrays-with-odd-sum/description/

题目分析

问题描述 :

给定一个整数数组 arr,返回其中和为奇数的子数组的数目。由于答案可能很大,结果需对 10^9 + 7 取余。

示例 :

输入:arr = [1, 3, 5]

输出:4

解释:

  • 子数组 [1]、[3]、[5] 的和均为奇数。
  • 子数组 [1, 3, 5] 的和为 1 + 3 + 5 = 9,也是奇数。

暴力解法(超时)

思路 :

枚举所有子数组,计算每个子数组的和并判断奇偶性。

代码:

cpp 复制代码
class Solution {
public:
    int numOfSubarrays(vector<int>& arr) {
        const int MOD = 1e9 + 7;
        int count = 0;
        int n = arr.size();
        
        for (int i = 0; i < n; i++) {
            int sum = 0;
            for (int j = i; j < n; j++) {
                sum += arr[j];
                if (sum % 2 == 1) {
                    count = (count + 1) % MOD;
                }
            }
        }
        return count;
    }
};

复杂度:

  • 时间复杂度:O(n²)
  • 空间复杂度:O(1)

优化解法:前缀和 + 奇偶计数

核心思路:

  1. 前缀和的奇偶性 :子数组 [i, j] 的和为 prefix[j+1] - prefix[i],其中 prefix[k] 表示前 k 个元素的和。
  2. 奇偶性规律 :若 prefix[j+1] 和 prefix[i] 的奇偶性不同,则子数组和为奇数。
  3. 哈希表统计:动态维护前缀和为奇数和偶数的次数,遍历数组时累加符合条件的子数组数目。

代码:

cpp 复制代码
class Solution {
public:
    int numOfSubarrays(vector<int>& arr) {
        const int MOD = 1e9 + 7;
        int count = 0;
        int prefix = 0;      // 当前前缀和
        int odd = 0;         // 前缀和为奇数的次数
        int even = 1;        // 前缀和为偶数的次数(初始包含前缀和为0的情况)
        
        for (int num : arr) {
            prefix += num;
            if (prefix % 2 == 0) {
                // 当前前缀和为偶数,加上之前前缀和为奇数的次数
                count = (count + odd) % MOD;
                even++;
            } else {
                // 当前前缀和为奇数,加上之前前缀和为偶数的次数
                count = (count + even) % MOD;
                odd++;
            }
        }
        return count;
    }
};

复杂度:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

详细解释

  1. 前缀和的奇偶性 :

    对于子数组 [i, j],其和为 prefix[j+1] - prefix[i]。

    • 若 prefix[j+1] 为偶数,prefix[i] 为奇数,则和为奇数。
    • 若 prefix[j+1] 为奇数,prefix[i] 为偶数,则和为奇数。
  2. 动态维护奇偶次数:

    • odd:记录遍历到当前位置时,前缀和为奇数的次数。
    • even:记录遍历到当前位置时,前缀和为偶数的次数。
    • 初始值 :even = 1,因为空数组的前缀和为 0(偶数)。
  3. 累加结果:

    • 若当前前缀和为偶数,则它可以与之前所有奇数前缀和形成有效子数组,累加 odd。
    • 若当前前缀和为奇数,则它可以与之前所有偶数前缀和形成有效子数组,累加 even。

示例验证

输入:arr = [1, 3, 5]

步骤如下:

  1. 初始状态 :prefix = 0,odd = 0,even = 1,count = 0。
  2. 处理 1 :prefix = 1(奇数),count += even = 1,odd = 1,even = 1。
  3. 处理 3 :prefix = 4(偶数),count += odd = 1 + 1 = 2,odd = 1,even = 2。
  4. 处理 5 :prefix = 9(奇数),count += even = 2 + 2 = 4,odd = 2,even = 2。

最终结果:4,与预期一致。

总结

通过前缀和的奇偶性分析和动态计数,我们将时间复杂度从 O(n²) 优化到 O(n),空间复杂度为 O(1)。这种方法适用于所有类似的"子数组和满足某种奇偶性条件"的问题,核心在于利用前缀和的奇偶性快速查找配对。

相关推荐
罗湖老棍子3 小时前
Biorhythms(信息学奥赛一本通- P1639)
算法·数论·裴蜀定理·扩展欧几里得·扩展中国剩余定理
奋发向前wcx8 小时前
CSP-J复赛模拟赛4 王晨旭补题 2026.10.5
算法
念何架构之路11 小时前
zap采样器与性能优化内幕
算法·性能优化·哈希算法
晒太羊的猫11 小时前
hot100动态规划刷题
算法·动态规划
weixin_5310946912 小时前
heap_4内存管理
java·开发语言·算法
余额瞒着我当琳12 小时前
红黑树的实现--红黑树的概念、规则、效率、结构、旋转、查找、验证
数据结构·c++·算法
程序员南飞12 小时前
win系统安装minio
java·数据结构·算法
青少儿编程课堂12 小时前
AC自动机多模式串匹配精讲:校园关键词巡检实战解析
c++·python·算法·bfs·信息学竞赛
longlongzihan13 小时前
LeetCode 5. 最长回文子串:从暴力匹配到中心扩展的思维演进
c++·算法·leetcode
waoooqwe13 小时前
问卷样本真实吗
大数据·数据库·算法·数据分析