前缀和与差分

        前缀和与差分是计算机科学中常用的算法技术,它们主要用于高效地处理区间求和和区间修改的问题。这两者可视作互逆的操作。

一、前缀和

        前缀和是一个序列的前n项和的集合,通常用于快速计算某个区间的和。我们设定数组a[]为原始数组,定义一个前缀和数组s[],其中s[i]表示a[1]a[i]的和。

1. 前缀和的计算

前缀和的计算公式如下:

  • 初始化:s[0] = 0
  • 推递公式:s[i] = s[i-1] + a[i]

        通过上述方法,我们可以在O(n)的时间复杂度内构建前缀和数组。对于任意的区间 [l, r],可以快速计算出其和,公式为:

  • sum(l, r) = s[r] - s[l-1]

这样就将区间求和的时间复杂度降到了O(1)

2.前缀和的代码示例

import java.util.Scanner;

public class PrefixSum {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 输入数组的大小
        int n = sc.nextInt();
        int[] arr = new int[n + 1]; // 原始数组,1-indexed
        int[] prefixSum = new int[n + 1]; // 前缀和数组,1-indexed

        // 填充原始数组
        for (int i = 1; i <= n; i++) {
            arr[i] = sc.nextInt();
        }

        // 计算前缀和
        for (int i = 1; i <= n; i++) {
            prefixSum[i] = prefixSum[i - 1] + arr[i]; // 前缀和的递推
        }

        // 输入需要查询的区间
        int l = sc.nextInt();
        int r = sc.nextInt();

        // 使用前缀和计算区间和
        int sum = prefixSum[r] - prefixSum[l - 1]; // 区间和公式
        System.out.println("区间和:" + sum);
    }
}

3.代码解析

        在代码中,用户首先输入数组的大小 n 和元素。

        随后,生成前缀和数组 prefixSum[]。通过用户输入的查询区间 [l, r],使用公式 sum = prefixSum[r] - prefixSum[l - 1] 快速计算得出该区间内的和。

        这种方式将单次查询的时间复杂度降低到 O(1),提高了整体效率。

二、差分

        差分是前缀和的逆运算,主要用于快速更新区间。它允许我们在常数时间内对数组的区间进行加减操作。

1. 差分的概念

设数组 b[] 为差分数组,那么原数组 a[] 和差分数组之间的关系可以用以下公式表示:

  • a[i] = b[1] + b[2] + ... + b[i]

差分数组的构造也很简单:

  • b[1] = a[1]
  • b[i] = a[i] - a[i-1] (对于 i > 1)

 区间更新

对区间 [L, R] 增加一个常数 C,可以通过以下两步在差分数组中实现:

  • b[L] += C
  • b[R + 1] -= C

 这种操作的时间复杂度为O(1)。求出更新后的原数组 a[] 只需对差分数组进行前缀和计算即可

2.差分的代码示例

import java.util.Scanner;

public class DifferenceArray {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 输入数组的大小
        int n = sc.nextInt();
        int[] arr = new int[n + 1]; // 原始数组,1-indexed
        int[] diff = new int[n + 2]; // 差分数组,1-indexed,额外加一以处理边界

        // 填充原始数组
        for (int i = 1; i <= n; i++) {
            arr[i] = sc.nextInt();
        }

        // 构造差分数组
        diff[1] = arr[1]; // 第一个元素
        for (int i = 2; i <= n; i++) {
            diff[i] = arr[i] - arr[i - 1]; // 差分公式
        }

        // 更新区间 [L, R] 加上 C
        int L = sc.nextInt();
        int R = sc.nextInt();
        int C = sc.nextInt();
        diff[L] += C; // 开始位置增加 C
        diff[R + 1] -= C; // 结束位置后一个位置减少 C

        // 将差分数组转化回原始数组
        for (int i = 1; i <= n; i++) {
            arr[i] = arr[i - 1] + diff[i]; // 恢复原数组
            System.out.print(arr[i] + " "); // 输出更新后的数组
        }
    }
}

3.代码解析

        在代码中,用户输入原始数组的元素,通过差分计算每个元素与前一个元素之间的差值。

        通过用户输入的区间 [L, R],在差分数组中进行更新,分别在 diff[L] 和 diff[R + 1] 进行加减操作。

        最后,通过对差分数组进行前缀和计算,恢复更新后的原数组。

总结

        了解前缀和与差分,不仅能有效提高区间和查询的效率,还能快速处理区间更新。掌握这些算法,可以帮助我们解决许多实际编程挑战,使我们在面对大数据时更加得心应手。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值