493. 翻转对 - 力扣

65 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

题目

493. 翻转对 - 力扣(LeetCode)

这次有现成的题目,所以大家可以点击一下去看看。

思路

这个题目其实和我之前讲过的逆序对是一样的,没有看过的可以去了解一下,可以更好理解

逆序对问题详情 - 掘金 (juejin.cn)

对于这个问题也是一样的需要归并的思想,只是逆序对问题不用乘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)的。