这是一道利用前缀和+哈希表进行动态统计的题目。核心思路是枚举“修改哪个元素”,并快速计算出此时产生多少个合法分割点。

题意分析

  • 你可以选择修改1个元素k(也可以不修改)。
  • 在数组中间切一刀,分成左右非空的两部分,使左和等于右和。
  • 求通过最多一次修改,最多能有多少种不同的切法

设:

  • total = 原数组总和
  • 修改 nums[i]k,差值为 d = k - nums[i]
  • 新总和 total' = total + d
  • 分割点 p0 ≤ p < n-1)左部分和为 pre[p]

当修改位置 i 与 p 的关系不同,新的左和也不同:

关系 新左和 等式条件
i ≤ p pre[p] + d pre[p] = (total - d) / 2
i > p pre[p] pre[p] = (total + d) / 2

只要 total' 为偶数,再分别统计满足上述值的 p 的个数即可。

算法步骤

  1. 计算原数组前缀和 pre,并用哈希表 freq 统计 pre[0..n-2] 的频率(因为 p 最大为 n-2)。
  2. 不修改的情况:若 total 为偶数,答案初始化为 freq[total/2]
  3. 维护左右两个哈希表:
    • right:初始为全部合法 p 的前缀和频率(即 freq 拷贝)。
    • left:初始为空。
  4. 遍历 i0n-1
    • 计算 d = k - nums[i],若 total + d 是偶数,则:
      • left(total + d)/2 的个数
      • right(total - d)/2 的个数
      • 相加得当前修改的方案数,更新答案。
    • i < n-1,将 p = iright 移到 left(因为下一轮 i+1 时,p=i 将属于 i > p 的情况)。
  5. 返回答案。

TypeScript 实现

function waysToPartition(nums: number[], k: number): number {
    const n = nums.length;
    const pre: number[] = new Array(n);
    pre[0] = nums[0];
    for (let i = 1; i < n; i++) {
        pre[i] = pre[i - 1] + nums[i];
    }
    const total = pre[n - 1];

    // 统计所有合法分割点 p ∈ [0, n-2] 的前缀和频率
    const freq = new Map<number, number>();
    for (let p = 0; p < n - 1; p++) {
        const val = pre[p];
        freq.set(val, (freq.get(val) ?? 0) + 1);
    }

    // 不修改的情况
    let ans = 0;
    if (total % 2 === 0) {
        ans = freq.get(total / 2) ?? 0;
    }

    const left = new Map<number, number>();
    const right = new Map(freq);   // 初始全部 p 在 right

    for (let i = 0; i < n; i++) {
        const d = k - nums[i];
        const newTotal = total + d;

        if (newTotal % 2 === 0) {
            const targetLeft = newTotal / 2;          // i > p 时的目标值
            const targetRight = (total - d) / 2;      // i ≤ p 时的目标值
            const cnt = (left.get(targetLeft) ?? 0) + (right.get(targetRight) ?? 0);
            if (cnt > ans) ans = cnt;
        }

        // 将 p = i 从 right 移动到 left(如果 i 是合法的分割点)
        if (i < n - 1) {
            const val = pre[i];
            right.set(val, (right.get(val) ?? 0) - 1);
            left.set(val, (left.get(val) ?? 0) + 1);
        }
    }

    return ans;
}

复杂度

  • 时间O(n) —— 遍历数组 + 哈希表操作。
  • 空间O(n) —— 存储前缀和及两个哈希表。

此解法可以处理 n ≤ 10⁵、值域 ±10⁷ 的大数据规模,且在 JavaScript/TypeScript 的安全整数范围内。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐