首页 > 试题广场 >

数组中的逆序对

[编程题]数组中的逆序对
  • 热度指数:846830 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007

数据范围:  对于 的数据,
对于 的数据,
数组中所有数字的值满足 0 \le val \le 10^9

要求:空间复杂度 ,时间复杂度

输入描述:
题目保证输入的数组中没有的相同的数字

示例1

输入

[1,2,3,4,5,6,7,0]

输出

7
示例2

输入

[1,2,3]

输出

0
// 暴力解法
    public int InversePairs1 (int[] nums) {
        long count = 0;
        for(int i=0;i<nums.length-1;i++){
            for(int j = i+1;j<nums.length;j++){
                if(nums[i] > nums[j]){
                    count++;
                }
            }
        }
        return (int)(count % 1000000007);
    }
    // 插入排序
    public int InversePairs2 (int[] nums) {
        long count = 0;
        ArrayList<Integer> list = new ArrayList<>();
        list.add(nums[nums.length-1]);
        for(int i=nums.length-2;i >= 0;i--){
            count += InversePairs_insert(list,nums[i]);
        }
        return (int)(count % 1000000007);
    }

    public int InversePairs_insert (ArrayList<Integer> list,int data) {
        int s=0,e=list.size()-1;
        int mid = 0;
        while(s<=e){
            mid = (s+e)/2;
            if(list.get(mid) == data){
                break;
            }else if(list.get(mid) > data){
                e = mid - 1;
            }else{
                s = mid + 1;
            }
        }
        if(s > mid){
            list.add(mid+1,data);
            return mid + 1;
        }else{
            list.add(mid,data);
            return mid;
        }
    }
    // 归并
    public int InversePairs (int[] nums) {
        if(nums.length < 2) return 0;
        int[] temp = new int[nums.length];
        int count = InversePairs_sort(nums,0,nums.length-1,temp);
        return count;
    }

    public int InversePairs_sort(int[] nums,int s,int e,int[] temp) {
        if(s >= e) return 0;
        int mid = (s+e)/2;
        int res = InversePairs_sort(nums,s,mid,temp) 
                + InversePairs_sort(nums,mid+1,e,temp);
        res = res % 1000000007;
        int i = s,j = mid+1;
        for(int k=s;k<=e;k++){
            temp[k] = nums[k];
        }
        for(int k=s;k<=e;k++){
            if(i == mid+1){
                nums[k] = temp[j++];
            }else if(j == e+1 || temp[i] <= temp[j]){
                nums[k] = temp[i++];
            }else{
                nums[k] = temp[j++];
                res += mid - i + 1;
            }
        }
        return res % 1000000007;
    }

发表于 2024-08-20 17:51:05 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int InversePairs (int[] nums) {
        // write code here
        // 左程云老师讲过,通过归并排序过程中的左右两个字串的比较,可以实现逆序对的统计

        // 算法的时间复杂度O(NlogN),空间复杂度O(N)

        // 调用归并排序的递归执行方法
        int count = process(nums, 0, (nums.length - 1));
        // 注意题目要求,对1000000007取模
        return count % 1000000007;
    }

    // 递归执行方法
    public int process(int[] nums, int l, int r) {
        // 递归出口
        if (l == r) {
            return 0;
        }
        // 计算中间索引
        int mid = (l + r) / 2;
        // 返回递归过程产生的逆序对数量
        int count = process(nums, l, mid) +
                    process(nums, mid + 1, r) +
                    compareAndMerge(nums, l, mid, r);
        // 注意题目要求,对1000000007取模
        return count % 1000000007;
    }

    // 比较与归并方法
    public int compareAndMerge(int[] nums, int l, int mid, int r) {
        // 记录逆序对的个数
        int count = 0;

        // 比较,归并
        int[] tempNums = new int[r - l + 1];
        // nums的左半区下标
        int leftIndex = l;
        // nums的右半区下标
        int rightIndex = mid + 1;
        // tempNums的下标
        int tempIndex = 0;
        while (leftIndex <= mid && rightIndex <= r) {
            // 请注意,归并排序merge的一个前提是,左右两个半区各自有序
            if (nums[leftIndex] < nums[rightIndex]) {
                // 左边 < 右边,则左边先进入tempNums中,leftIndex和tempIndex都++
                tempNums[tempIndex] = nums[leftIndex];
                leftIndex++;
            } else {
                // 左边 > 右边,则右边先进入tempNums中,rightIndex和tempIndex都++
                // 注意!此时算作逆序对!
                tempNums[tempIndex] = nums[rightIndex];
                rightIndex++;
                // tempNums[leftIndex]大,说明从leftIndex到mid上的数都更大,逆序数要全算上
                count += (mid - leftIndex + 1);
                // 注意题目要求,对1000000007取模
                count %= 1000000007;
            }
            tempIndex++;
        }
        // 此时退出了循环,要么leftIndex越界,要么rightIndex越界,以下两个while最多执行一个
        while (leftIndex <= mid) {
            // 右边的rightIndex先越界了,说明左边剩下的元素都比右边的大,把左边剩下的元素全部送进tempNums中
            // 注意!这里的逆序对已经被上一个while中考虑到了
            tempNums[tempIndex] = nums[leftIndex];
            leftIndex++;
            tempIndex++;
        }
        while (rightIndex <= r) {
            // 左边的leftIndex先越界了,说明右边剩下的元素都比左边的大,把右边剩下的元素全部送进tempNums中
            tempNums[tempIndex] = nums[rightIndex];
            rightIndex++;
            tempIndex++;
        }

        // 最后,把tempNums排好序的内容写回nums的对应位置
        for (int i = 0; i < tempNums.length; i++) {
            nums[l + i] = tempNums[i];
        }

        // 返回统计到的逆序数
        return count;
    }
}

发表于 2024-07-27 19:48:44 回复(0)
//这里用的是官方题解,我做了一些更详细的注释,希望可以帮到一些朋友



import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
     int mod = 1000000007;
    public int mergeSort(int left, int right,int[] data,int[] temp) {
        //将数组分开
        if(left >= right) {
            return 0;
        }
        int mid = (left + right) / 2;
        int res = mergeSort(left,mid,data,temp) + mergeSort(mid + 1,right,data,temp);
        //下面的代码本质上是将数组合并,并且排序,顺便给逆序对进行计数
        res %= mod;
        //两端数组
        int i = left;//左边数组第一个元素
        int j = mid + 1;//右边数组第一个元素
        //将两段数组添加到一个临时数组中
        for(int k = left; k <= right; k++) {
            temp[k] = data[k];
        }
        for(int k = left; k <= right; k++) {
            if(i == mid + 1) {//左边数组已经遍历完
                data[k] = temp[j++];
            }else if(j == right + 1 || temp[i] <= temp[j]) {//右边数组已经遍历完或者左边元素小于右边元素
                data[k] = temp[i++];
            }else {
                data[k] = temp[j++];//左边元素大于右边元素,此时出现逆序对,进行计数
                res += mid - i + 1;//res是下一层数组逆序对的结果,由于两边数组都是有序的,左边的某一个元素大于右边的某一个元素,那么左边后面的所有元素都比右边的哪一个元素大,因此要加上mid - i + 1
            }
        }
        return res % mod;
    }

    public int InversePairs (int[] nums) {
        // write code here
        int left = 0;
        int right = nums.length - 1;
        int[] res = new int[right + 1];
        return mergeSort(left,right,nums,res);
    }
}
发表于 2024-03-20 22:09:52 回复(0)
终于过了,最后一个用例也太逆天了
public class Solution {
    public int InversePairs(int[] nums) {
        int left = 0, right = nums.length - 1;
        return (int)(mergeSort(nums, left, right) % 1000000007);
    }

    private long mergeSort(int[] nums, int left, int right) {
        if (left == right) {
            return 0;
        }
        int mid = left + ((right - left) >> 1);
        long x1 = mergeSort(nums, left, mid);
        long x2 = mergeSort(nums, mid + 1, right);
        long x3 = merge(nums, left, mid, mid + 1, right);
        return x1 + x2 + x3;
    }

    private long merge(int[] nums, int l1, int l2, int r1, int r2) {
        int[] temp = new int[r2 - l1 + 1];
        int i = 0;
        int l = l1;
        long count = 0;  
        while (l1 <= l2 && r1 <= r2) {
            if (nums[l1] > nums[r1]) {
                count = count + r2 - r1 + 1;
                temp[i++] = nums[l1++];
            } else {
                temp[i++] = nums[r1++];
            }
        }
        while (l1 <= l2) {
            temp[i++] = nums[l1++];
        }
        while (r1 <= r2) {
            temp[i++] = nums[r1++];
        }

        // 放回原来的数组
        i = 0;
        for (int i1 = l; i1 <= r2; i1++) {
            nums[i1] = temp[i++];
        }
        return count;
    }
}


发表于 2024-01-20 19:29:41 回复(1)

归并排序

public class Solution {
    public static final int MOD = 1000000007;

    public int InversePairs (int[] nums) {
        return mergeSort(nums, 0, nums.length - 1);
    }

    public int mergeSort(int[] nums, int l, int r) {
        if (l == r) {
            return 0;
        } 
        int mid = (l + r) >> 1;
        int lres = mergeSort(nums, l, mid);
        int rres = mergeSort(nums, mid + 1, r);

        int left = l, right = mid + 1, ans = (lres + rres) % MOD;
        int[] tmp = new int[r - l + 1];
        int idx = 0;
        while (left <= mid && right <= r) {
            if (nums[left] <= nums[right]) {
                tmp[idx++] = nums[left++];
            } else {
                tmp[idx++] = nums[right++];
                ans = (ans + mid - left + 1) % MOD;
            }
        } 
        while (left <= mid) tmp[idx++] = nums[left++];
        while (right <= r) tmp[idx++] = nums[right++];
        for (int i = 0; i < idx; i++) {
            nums[l + i] = tmp[i];
        }

        return ans;
    }
}
发表于 2023-11-11 15:11:11 回复(0)
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param nums int整型一维数组
     * @return int整型
     */
    public int InversePairs (int[] nums) {
        long total=0;
        for (int i = 0; i < nums.length; i++) {
            for (int j = i+1; j <nums.length; j++) {
                if (nums[i]>nums[j]){
                    total++;
                }
            }
        }
        return (int) (total%1000000007);
    }
}

发表于 2023-10-20 20:05:53 回复(2)
// 归并排序,计算左边到右边的逆序对
public class Solution {
    long n;
    public int InversePairs (int[] nums) {
        int[] tmp = new int[nums.length];
        mergeSort(nums, tmp, 0, nums.length - 1);
        return (int)(n % 1000000007);
    }
    public void mergeSort(int[] nums, int[] tmp, int l, int r) {
        if (l < r) {
            int c = (l + r) / 2;
            mergeSort(nums, tmp, l, c);
            mergeSort(nums, tmp, c + 1, r);          
            mergeAscend(nums, tmp, l, c, r);
        }

    }

    private void mergeAscend(int[] nums, int[] tmp, int l, int c, int r) {
        int l1 = l, r1 = c, l2 = c + 1, r2 = r;
        int i = l1;
        while (l1 <= r1 && l2 <= r2 ) {
            if (nums[l1] <= nums[l2]) {
                tmp[i++] = nums[l1++];
            } else {
                n += (r1 -l1 + 1);
                tmp[i++] = nums[l2++];
            }
        }
        while (l1 <= r1) {
            tmp[i++] = nums[l1++];
        }
        while (l2 <= r2) {
            tmp[i++] = nums[l2++];
        }
        for (i = l; i <= r; i++) {
            nums[i] = tmp[i];
        }
    }
}
发表于 2023-09-16 21:39:41 回复(0)
import java.util.*;

public class Solution {
    public int InversePairs(int [] array) {
        long sum = 0;
        for (int i = 1; i < array.length; i++) {
            int values = array[i];
            int[] ints = Arrays.copyOfRange(array, 0, i + 1);
            Arrays.sort(ints);
            int index = Arrays.binarySearch(ints, values);
            sum += (i - index);
        }
        return (int)(sum % 1000000007);

    }
}
发表于 2023-03-23 17:08:33 回复(1)
通过率83.3%,不足是运行超时,代码没毛病。
public class Solution {
    public int InversePairs(int [] array) {
        if (array == null || array.length == 0) return -1;
        int count = 0;
        for (int i = 0; i < array.length - 1; i++) {
            for (int j = i; j < array.length - 1; j++) {
                if (array[i] > array[j + 1])  count++;
            }
        }
        return count % 1000000007;
    }
}


发表于 2023-03-19 20:57:05 回复(2)
public class Solution {
    int flag = 0;
    public int InversePairs(int [] array) {
            process(array,0,array.length-1);
            return flag ;
        }
        public void process(int[] arr, int l, int r) {
            if (l == r) {
                return;
            }
            int m = l + ((r - l) >> 1);
            process(arr, l, m);
            process(arr, m + 1, r);
            merge(arr, l, r);
        }
        public void merge(int[] arr, int left, int right) {
            int mid = left + ((right - left) >> 1);
            int[] temp = new int[right - left + 1];
            int i = left;
            int j = mid + 1;
            int k = 0;
            while (i <= mid && j <= right) {
                if (arr[i] > arr[j]) {
                    temp[k++] = arr[j++];  //右边的小,小的加入辅助数组
                flag+=mid-i+1;  //右边的小说明有逆序对,因为每次两个部分都是排好序的所以arr[i]以及以后都比arr[j]大
                flag %=1000000007;
            }else {
                temp[k++] = arr[i++];
            }
        }
        if (i<=mid) {
            int x = i;
            while (i <= mid) {
                temp[k++] = arr[i++];
            }
            flag += (mid-i+1)*(right-mid);  //左边的多了说明在arr[i]以及以后都比右部分大所以这里乘了(right-mid)
            flag %=1000000007;
            }
            while (j <= right) {
                temp[k++] = arr[j++];
            }
            for (int i1 = 0; i1 < temp.length; i1++) {
                arr[i1 + left] = temp[i1];
            }
        }
}

发表于 2023-03-16 22:13:36 回复(0)
public class Solution {
    public int InversePairs(int [] array) {
        if(array.length == 0) return 0;
        long P =0L;
        for(int i =0; i < array.length - 1; i++)
            for(int j = i + 1; j < array.length; j++){
                if(array[i] > array[j]) P++;
            }
        return (int)(P % 1000000007);
    }
}
这个代码是不是时间复杂度是O(n^2)?虽然通过了,冒泡排序再怎么优化都是n^2吗?
发表于 2023-03-08 16:57:38 回复(1)
参考高赞@rs勿忘初心 的思路,使用Java语言实现。
这里count的取模放到最后会抛出异常,需要放到每次计算的过程中
public class Solution {
    public int InversePairs(int [] array) {
        if(null == array || array.length <= 1){
            return 0;
        }

        return getCount(array,0,array.length-1,new int[array.length]);

    }

    private int getCount(int[] array,int start,int end,int[] copy){
        if(start >= end) {
            copy[start] = array[start];
            return 0;
        }

        int count = 0;
        int mid = start + (end - start) / 2;
        count += getCount(array,start,mid,copy);
        count += getCount(array,mid + 1,end,copy);

        int i = mid;
        int j = end;
        int copyIndex = end;
        while (i >= start && j > mid){
            if(array[i] > array[j]){
                copy[copyIndex--] = array[i--];
                count += j - mid;
                count = count % 1000000007;
            }
            else{
                copy[copyIndex--] = array[j--];
            }
        }
        while (i >= start){
            copy[copyIndex--] = array[i--];
        }
        while (j > mid){
            copy[copyIndex--] = array[j--];
        }

        for(int k = start;k <= end;k++){
            array[k] = copy[k];
        }

        return count;
    }
}


发表于 2023-03-03 11:49:35 回复(1)
//归并排序Java版
public class Solution {
    int count=0;
    public int InversePairs(int [] array) {
        mergeSort(array,0,array.length-1);
        return count;
    }

    public void mergeSort(int [] array, int left, int right){
        if(left >= right) return;
        int mid = (left+right)/2;
        mergeSort(array, left, mid);
        mergeSort(array, mid+1, right);
        merge(array, left, mid, right);
    }

    public void merge(int [] array, int left, int mid, int right){
        int[] temp=new int[right-left+1];
        int i=left, j=mid+1;
        int t=0;

        while(i<=mid && j<=right){
            if(array[i]<=array[j]){
                temp[t++]=array[i++];
            }else{
                count=count+(mid-i+1);
                count%=1000000007; //在这里取模
                temp[t++]=array[j++];
            }
        }

        while(i<=mid){
            temp[t++]=array[i++];
        }
        while(j<=right){
            temp[t++]=array[j++];
        }

        for(int k=0;k<temp.length;k++){
            array[left+k]=temp[k];
        }
        
    }
}

发表于 2023-02-05 11:31:45 回复(2)
public int InversePairs(int[] array) {
if (array == null || array.length == 1) {
return 0;
}
return mergeSort(array, 0, array.length - 1);
}

private int mergeSort(int[] array, int left, int right) {
if (left == right) {
return 0;
}
int mid = left + ((right-left)>>1);
int result = mergeSort(array, left, mid)
+ mergeSort(array, mid + 1, right)
+ merge(array, left, mid, right);
return (result%1000000007);
}

private int merge(int[] array, int left, int mid, int right) {
int[] help = new int[right - left + 1];
int p1 = mid;
int p2 = right;
int reverseNum = 0;
int i = help.length - 1;
while (p1 >= left && p2 > mid) {
if (array[p1] > array[p2]) {
reverseNum += (p2 - mid);
help[i--] = array[p1--];
} else {
help[i--] = array[p2--];
}
}
while (p1 >= left) {
help[i--] = array[p1--];
}
while (p2 > mid) {
help[i--] = array[p2--];
}
for (int j = 0; j < help.length; j++) {
array[left + j] = help[j];
}
return reverseNum%1000000007;
}
发表于 2022-11-23 20:07:24 回复(0)
我这个算不算暴力解法呀
public class Solution {
    public int InversePairs(int [] array) {
        if(array.length==0 || array.length==1)return 0;
        int fast = 1;
        int slow = 0;
        long count = 0;
        while(slow<array.length-1){
            if(array[slow]>array[fast]){
                count++;
            }
            fast++;
            if(fast==array.length){
                slow++;
                fast=slow+1;
            } 
        }
        return (int)(count % 1000000007);
    }
}
发表于 2022-11-12 14:01:48 回复(3)
public class Solution {
    public int InversePairs(int [] array) {
        if (array == null || array.length <= 0 ) {
            return 0;
        }
        int[] temp = new int[array.length];
        return sort(array, 0, array.length-1, temp) % 1000000007;

    }
    private int sort(int[] array, int left, int right, int[] temp) {
        if (left == right) {
            return 0;
        }
        int mid = (right - left) / 2 + left;
        int leftPairCount = sort(array, left, mid, temp);
        int rightPairCount = sort(array, mid + 1, right, temp);
        int tmpPairCount = merge(array, left, mid, right, temp);
        return leftPairCount + rightPairCount + tmpPairCount;

    }

    private int merge(int[] array, int left, int mid, int right, int[] temp) {
        int start1 = left;
        int start2 = mid + 1;
        int index = 0;
        int computeReversePairs = 0;
        while (start1 <= mid && start2 <= right) {

            if (array[start1] <= array[start2]) {
                temp[left + index] = array[start1];
                start1++;

            } else {
                temp[left + index] = array[start2];
                start2++;
                computeReversePairs = (computeReversePairs+(mid-start1+1))%1000000007;
            }
            index++;
        }

        while (start1 <= mid) {
            temp[left + index] = array[start1];
            start1++;
            index++;
        }
        while (start2 <= right) {
            temp[left + index] = array[start2];
            start2++;
            index++;
        }
        //将temp覆盖原来的数组中的顺序
        while (left <= right) {
            array[left] = temp[left];
            left++;
        }
        return computeReversePairs;
    }
}

发表于 2022-11-01 13:38:12 回复(0)
其实就是归并排序,在左边比右边绝对大的时候  再进行计count += 左边当前共有的多少数
public class Solution {
    public int mod = 1000000007;
    public int InversePairs(int [] arr) {
        if(arr == null || arr.length <= 1){
            return 0;
        }
        int[] temp = new int[arr.length];
        return InversePairs(arr, 0, arr.length - 1, temp);
    }

    public int InversePairs(int [] arr, int left, int right,int[] temp) {
        if(left >= right){
            return 0;
        }
        int mid = left + (right - left ) / 2;

        int val1 = (InversePairs(arr, left, mid, temp) + InversePairs(arr, mid + 1, right, temp)) % mod;


        if(arr[mid] <= arr[mid + 1]){
            return val1;
        }

        int l = left, r = mid + 1 ,count = 0,
        tempI = 0;
        while (l <= mid && r <= right){
            if(arr[l] > arr[r]){
                temp[tempI] = arr[r];
                r++;
                // 左边比右边绝对大时 count+= 左边当前共有多少数的数量
                count +=  mid + 1 - l;
            }else{
                temp[tempI] = arr[l];
                l++;
            }
            tempI++;
        }

        while (l <= mid){
            temp[tempI] = arr[l];
            l++; tempI++;
        }
        while (r <= right){
            temp[tempI] = arr[r];
            r++; tempI++;
        }

        tempI = 0;
        for (int i = left; i <= right; i++,tempI++) {
            arr[i] = temp[tempI];
        }
        return (val1 + count)  % mod;
    }
}   


发表于 2022-10-31 01:36:05 回复(0)