差分数组-生存人数

刷leetcode碰到生存人数一题,有使用差分数组进行求解的,看到很多题解都是直接贴代码,没有差分数组原理的讲解,看的云里雾里的,遂查了一下差分数组的原理和使用场景,茅塞顿开!!

题目:生存人数

代码:

public int maxAliveYear(int[] birth, int[] death) {
    int[] dp = new int[102];
    for (int i = 0; i < birth.length; ++i) {
        dp[birth[i] - 1900] += 1;
        // 这里要注意,当年死的人还算在当年的人数,所以是下一年少一人
        dp[death[i] - 1900 + 1] -= 1;
    }
    int start = 0;
    int max = 0;
    int maxYear = 0;
    for (int i = 0; i < 102; ++i) {
        start += dp[i];
        if (start > max) {
            max = start;
            maxYear = i;
        }
    }
    return maxYear + 1900;
}

使用场景

如果给你一个包含5000万个元素的数组,然后会有频繁区间修改操作,比如让第1个数到第1000万个数每个数都加上1,而且这种操作是频繁的。此时应该怎么做?很容易想到的是,从第1个数开始遍历,一直遍历到第1000万个数,然后每个数都加上1,这种方法虽然可行,一旦区间操作频繁系统的压力就很大,因此产生了更优解:差分数组!!

差分数组原理

比如我们现在有一个数组arr,arr={0,2,5,4,9,7,10,0}

image-20220315112209463

那么差分数组是什么呢?其实差分数组本质上也是一个数组,我们暂且定义差分数组为d,差分数组d的大小和原来arr数组大小一样,而且d[i]=arr[i]-arr[i-1],且d[i]=0,它的含义是什么?就是原来数组i位置上的元素和i-1位置上的元素作差,得到的值就是d[i]的值。所以,例子中的arr数组其对应的差分数组值如下图所示。

image-20220315112932147

那么构造了这么个玩意有什么用呢?难道是来浪费宝贵的内存空间的?嗯,确实是来浪费宝贵的内存了,但是却换了时间上的高效。

现在我们有这么一个区间修改操作,即在区间1~4上,所有的数值都加上3。我们不要傻傻地遍历arr数组的[1,4]范围,然后再分别给每个值加上3,我们此时更改差分数组d即可。

显而易见,差分数组d在[2,4]范围内的值都不用改变,只需要改变差分数组位置1和位置5的值即可,即d[1]=d[1]+3,而d[5]=d[5]-3,其余不变,为什么呢?因为差分数组的定义——d[i]=arr[i]-arr[i-1]

image-20220315113956582

现在,我们如何根据差分数组d来推测arr中某一个位置的值呢?

比如,此时,我们想知道arr[1]的值,我们不能直接通过arr[1]得到原来的值,因为在区间修改的操作中我们并没有修改arr的值,因此我们必须从前往后遍历递推,由于d[0]=arr[0]-0(我们定义arr[0]的前一个数为0),那么arr[0]=d[0]=0,又由于d[1]=arr[1]-arr[0]=5,那么arr[1]=5+arr[0]=5。以此类推,由于d[2]=arr[2]-arr[1]=3,所以arr[2]=3+arr[1]=8。

总结

可以看到,如果需要对L~ R范围内所有数都进行相同的操作,我们不需要从L~R遍历arr然后在每个值上进行相同操作,只需要在差分数组d中改变L和R+1的值即可。但是在查询arr数组中某个位置的数时,却要根据差分数组从前往后递推求值。
所以,该方法适用于区间频繁修改,而且这个区间范围是比较大的,离线查询的情况。

### 差分数组的概念 差分数组是一种用于高效处理区间加减操作的数据结构。其核心思想是通过构建一个辅助数组来表示原数组相邻元素之间的差异,从而优化频繁修改区间的性能[^1]。 具体来说,对于给定的一个长度为 \(n\) 的数组 `arr`,可以创建一个同样长度的差分数组 `diff`,其中每个位置上的值定义如下: \[ \text{diff}[i] = \begin{cases} \text{arr}[0], & \text{if } i = 0 \\ \text{arr}[i] - \text{arr}[i-1], & \text{otherwise}. \end{cases} \] 这种转换使得我们可以快速更新某个区间 `[l, r]` 中的所有元素而无需逐一访问它们。 --- ### 差分数组的初始化方法 差分数组的初始化过程主要包括两个步骤: #### 步骤一:创建差分数组 首先,我们需要根据原始数组生成一个新的差分数组。这个新数组记录的是原数组中每一对连续项之差。 ```python def build_diff_array(arr): diff = [0] * len(arr) diff[0] = arr[0] for i in range(1, len(arr)): diff[i] = arr[i] - arr[i-1] return diff ``` 此函数接受输入数组并返回相应的差分数组。 #### 步骤二:应用差分运算 一旦有了初始状态下的差分数组之后,就可以利用它来进行高效的批量增减操作。例如当需要向指定范围内的多个数值增加相同常数时,只需调整该范围内首尾两端对应于差分表的位置即可完成整个区域的变化反映到最终结果上[^2]。 假设我们要对原始数据中的索引从第\( l \)至第\( r \)(包含边界)的部分均加上增量value,则只需要执行下面的操作: ```python def increment_range(diff, l, r, value): n = len(diff) if l >= n or r < 0 or l > r: return # 对起始位置进行累加 diff[l] += value # 如果结束位置不是最后一个元素,则对其后的第一个元素做相应减少 if (r + 1) < n: diff[r + 1] -= value ``` 最后再由经过这些改动后的差分数组重建回原来的数组形式得到新的实际存储版本的内容展示出来供后续调用查询使用。 --- ### 使用示例 以下是完整的例子展示了如何建立以及运用差分技术去解决特定场景下可能遇到的实际问题实例演示代码片段部分摘录自参考资料相关内容整理而成: ```python # 构建差分数组 original_array = [1, 2, 3, 4] diff = build_diff_array(original_array) print("Original Array:", original_array) print("Difference Array before modification:", diff) # 修改某一段区间的值 increment_range(diff, 1, 2, 2) # 还原成原数组的形式查看效果 reconstructed_array = [] current_sum = 0 for val in diff: current_sum += val reconstructed_array.append(current_sum) print("Reconstructed Original Array after modification:", reconstructed_array) ``` 运行以上程序将会打印出各个阶段的状态变化情况以便更好地理解整体流程逻辑走向规律特点等方面的信息呈现方式更加直观明了一些列动作产生的影响程度对比分析图表等等都可以作为进一步深入探讨学习研究方向之一考虑进去的话可能会更有助于掌握这项技能技巧要点所在之处哦! --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值