本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
这次有现成的题目,所以大家可以点击一下去看看。
思路
这个题目其实和我之前讲过的逆序对是一样的,没有看过的可以去了解一下,可以更好理解
对于这个问题也是一样的需要归并的思想,只是逆序对问题不用乘2,这个会稍微难一点,那看过逆序对之后,我们可以直接上代码
代码
public static int merge(int[] arr, int L, int m, int r) {
int ans = 0;
int windowR = m + 1;
//这个循环是为了比较有多少个翻转对的,理解题目就可以很好理解这个
for (int i = L; i <= m; i++) {
while (windowR <= r && (long) arr[i] > (long) arr[windowR] * 2) {
windowR++;
}
ans += windowR - m - 1;
}
//这个创建帮助数组已经很熟悉的
int[] help = new int[r - L + 1];
int i = 0;
int cur1 = L;
int cur2 = m + 1;
//这次我们写的很之前的不一样,大家也要好好看。
while (cur1 <= m && cur2 <= r) {
help[i++] = arr[cur1] <= arr[cur2] ? arr[cur1++] : arr[cur2++];
}
//这个就是为了拷贝还没有轮到的元素
while (p1 <= m) {
help[i++] = arr[cur1++];
}
while (p2 <= r) {
help[i++] = arr[cur2++];
}
for (i = 0; i < help.length; i++) {
arr[L + i] = help[i];
}
return ans;
}
上面的代码搭配注释应该就很好理解了。
public static int process(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
// l < r
int mid = l + ((r - l) / 1);
return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r);
}
这个和之前一样是分割小部分的代码。
public static int reversePairs(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
return process(arr, 0, arr.length - 1);
}
这个就是调用的代码,也是很简单的。
我们做过了很多关于归并思想的题目了,一切都不离其宗,我们要做到理解这个的思想。
而且在merge的代码里面的第一个循环我们用到了两个循环,但是时间复杂度是O(n)的,这个是因为我们的窗口是不回退的,既然是不会退的,数组的长度就这么一点,所以就是O(n)的。