前言
为什么会想到来讲解一下差分,主要还是最近的一场华为周赛最后一题考的就是差分,然而解出来的并不多,所以这篇文章可以来聊一聊差分是什么?
差分解决什么问题
举个例子吧,比如我们有十个区间[l, r],现在我们需要对这十个区间内的数都加一,按照我们最简单粗暴的方法就是遍历十个区间,依次对每个数进行加一操作,在区间数特别少且区间范围不大的情况下这当然可以,但是如果区间数量特别大,如有100000个区间,1 <= l <= r <= 100000,如果在这种情况下,如果我们还是用最暴力的方法来统计,那么复杂度是100000 * 100000,这复杂度已经是非常高了,那么一维差分是如何解决这个问题?
差分算法
给区间[l, r]的数都加一,我们可以简单的表示为 count[l]++, count[r+1]--,我们对所有的区间都执行这种记录,然后遍历count数组,执行count[i] += count[i-1]; 这种策略其实有点类似打表的思维,首先对区间进行打表,然后遍历统计数组count,计算结果。
有一维差分就必然有二维差分
举个简单的例子,我们有很多个矩形,现在我们要统计任意坐标被矩形覆盖的次数,也就是把上边讲的一维变成二维了,解决办法如法炮制,如矩形坐标[x1, y1, x2, y2],表示左上角与右小角,count[x1][y1]++,count[x2+1][y2+1]++,count[x1][y2+1]--,count[x2+1, y1]--; 可能只写出这个公式难以让人理解,可以把count[x][y],理解成以x,y为左上的顶点,它可以覆盖[x-无穷][y-无穷]的区间,那么我们统计矩形[x1, y1, x2, y2],就可以表示为 count[x1][y1] + count[x2+1][y2+1] - count[x1][y2+1] - count[x2+1][y1],自己画一下就能理解了
题目
简单表示就是给定50000个区间[l, r],1 <= l <= r <= 10^9,查询区间中任意数被覆盖次数,查询次数最多为50000次。
解法
有人看到区间范围是10 ^ 9顿时就怕了,觉得无法统计,那么你就错了,我们注意总共才50000个区间,最多查询50000次,那么最多出现150000个不同的数,我们把这些数离散化一下就好了
代码展示
/**
* 查询任意数被区间覆盖次数
* @param flowers 区间
* @param persons 查询具体的数
* @return
*/
public int[] fullBloomFlowers(int[][] flowers, int[] persons) {
int[] a = new int[2 * flowers.length + persons.length];
int cnt = 0;
for (int[] flower : flowers) {
a[cnt++] = flower[0];
a[cnt++] = flower[1];
}
for (int person : persons) {
a[cnt++] = person;
}
Arrays.sort(a);
Map<Integer, Integer> posMap = new HashMap<>();
for (int i = 0; i < a.length; i++) {
posMap.put(a[i], i + 1);
}
int[] count = new int[a.length + 10];
for (int[] flower : flowers) {
count[posMap.get(flower[0])]++;
count[posMap.get(flower[1]) + 1]--;
}
for (int i = 1; i < a.length + 10; i++) {
count[i] += count[i-1];
}
int[] ans = new int[persons.length];
for (int i = 0; i < persons.length; i++) {
ans[i] = count[posMap.get(persons[i])];
}
return ans;
}