基础算法--差分

差分(Difference numsay)用于高效地对数组进行区间更新操作。它通过记录数组相邻元素之间的差值,从而可以在常数时间内对某个区间内的元素进行增减操作。

差分数组的构造过程如下:

1、创建一个与原数组相同大小的差分数组 diff,初始值都为 0。
2、对于原数组 nums 的相邻元素 nums[i] 和 nums[i+1],将其差值存储在差分数组 diff[i] 中,即 diff[i] = nums[i+1] - nums[i]。

通过差分数组,我们可以在常数时间内对某个区间 [left, right] 内的元素进行增减操作,具体步骤如下:

1、假设要对原数组 nums 的区间 [left, right] 内的元素都增加一个值 val,即 nums[left] += val,nums[left+1] += val, …… ,nums[right] += val。
2、对应的差分数组 diff 的操作为 diff[left] += val 和 diff[right+1] -= val。

在差分数组中,未进行操作之前,diff[left]存储的值是nums[left]与nums[left-1]之间的差值,即diff[left] = nums[left] - nums[left-1]。当对nums[left]进行操作后,加上了一个值val,而nums[left-1]没有加上val,因此nums[left]与nums[left-1]之间的差值发生了变化,变为了nums[left]-nums[left-1]+val。
所以可以将这个变化后的差值表示为:

diff[left] += val

讨论完diff[left]的情况后,我们来看范围[left, right]内的元素差值是否有变化。假设left+1<=right,以diff[left+1]为例,未进行操作之前,diff[left+1]的值是nums[left+1]-nums[left]。在操作后,nums[left+1]和nums[left]都加上了val,所以范围[left, right]内diff值不变。

接下来再来看下diff[right+1],diff[right+1]比较特殊,它还要考虑是否会越界的问题,这里假设right+1小于数组长度,操作前,diff[right+1]=nums[right+1]-nums[right],操作后,nums[right]加了val,nums[right+1]没变,diff[right+1]=nums[right+1]-(nums[right]+val),化简后可得公式。

diff[right + 1] -= val

3、最后,根据差分数组 diff 可以还原回原数组 nums,即对差分数组 diff 进行前缀和操作。

下面是一个使用差分数组进行区间增减操作的示例代码:

public class Main {
    public static void main(String[] args) {
        int[] nums = {1, 2, 3, 4, 5};
        
        // 构造差分数组
        int n = nums.length;
        int[] diff = new int[n];
        diff[0] = nums[0];
        for (int i = 1; i < n; i++) {
            diff[i] = nums[i] - nums[i - 1];
        }
        
        // 对区间 [left, right] 内的元素增加 val
        int left = 1;
        int right = 3;
        int val = 2;
        diff[left] += val;
        if (right + 1 < n) {
            diff[right + 1] -= val;
        }
        
        // 根据差分数组构造结果数组
        int[] res = new int[n];
        res[0] = diff[0];
        for (int i = 1; i < n; i++) {
            res[i] = res[i - 1] + diff[i];
        }

        // 输出结果数组
        for (int i = 0; i < n; i++) {
            System.out.print(res[i] + " ");
        }
        System.out.println();
    }
}

应用实例:

3.字符串迁移

import java.util.Scanner;


public class d3 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int q = scanner.nextInt();
        int a[] = new int[n];
        int diff[] = new int[n + 1];
        char c[] = scanner.next().toCharArray();
        for (int i = 0; i < n; i++) a[i] = Integer.valueOf(c[i] - 'a');

        while (q-- > 0) {
            int l = scanner.nextInt() - 1;
            int r = scanner.nextInt() - 1;
            int k = scanner.nextInt() % 26;
            diff[l] += k;
            diff[r + 1] -= k;
        }
        for (int i = 1; i < diff.length; i++) diff[i] += diff[i - 1];
        for (int i = 0; i < n; i++) {
            int t = (a[i] + diff[i]) % 26;
            if (t < 0) t += 26; // 处理负数情况
            System.out.print((char) ('a' + t));
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值