Small Sum Problem (Merge Sort Counting)

用归并分治在 O(n log n) 内计算数组小和。

#resource / algorithm #type / howto #status / growing #algo / divide-and-conquer #algo / sort

[!info] related notes 算法面试题型 MOC 分治

Small Sum Problem

问题定义(常见版本):

  • 对数组中每个位置 j,统计它左侧所有 <= arr[j] 的数之和;把所有位置的这个和累加,得到“小和”。

分治视角

在 merge sort 的 merge 阶段:

  • 左半有序、右半有序。
  • 对右侧每个元素 arr[j],可以用双指针维护左侧所有 <= arr[j] 的前缀和,把贡献一次性加进去。

整体复杂度:O(n log n)

Java Template

import java.util.*;

public class SmallSum {
    static int[] arr;
    static int[] help;

    public static long smallSum(int[] nums) {
        if (nums == null || nums.length < 2) return 0;
        arr = nums;
        help = new int[nums.length];
        return solve(0, nums.length - 1);
    }

    static long solve(int l, int r) {
        if (l == r) return 0;
        int m = l + ((r - l) >> 1);
        return solve(l, m) + solve(m + 1, r) + mergeAndCount(l, m, r);
    }

    // returns small-sum contribution across left/right and merges sorted
    static long mergeAndCount(int l, int m, int r) {
        long ans = 0;

        // count cross contribution
        int i = l;
        long prefixSum = 0;
        for (int j = m + 1; j <= r; j++) {
            while (i <= m && arr[i] <= arr[j]) {
                prefixSum += arr[i++];
            }
            ans += prefixSum;
        }

        // standard merge
        int p1 = l, p2 = m + 1, k = l;
        while (p1 <= m && p2 <= r) {
            help[k++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= m) help[k++] = arr[p1++];
        while (p2 <= r) help[k++] = arr[p2++];
        for (int x = l; x <= r; x++) arr[x] = help[x];
        return ans;
    }
}
创建于 2026/3/16 更新于 2026/5/27