LeetCode-面试题51-数组中的逆序对
题目
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例1:
输入: [7,5,6,4]
输出: 5
说明:
0 <= 数组长度 <= 50000
解题思路
方法1、暴力破解(超时):
两个指针循环判断后面的数是不是小于前面的数,是就+1,但这样超时了。算一个没办法的解法吧
方法2、归并排序:
基本上代码就是归并排序的思想,但递归的终止条件有了变化,因为分裂区间需要判断是否有逆序数的关系
当区间的left==right的时候,说明这个区间只有一个数字了,一个数字不能组成逆序数,因此这个区间的逆序数为0
在跨区间逆序数计算时,如果左边区间比较小就需要先把左边区间的数放入temp数组中,这个时候代表左边的数比又边的数小,但此时不是逆序的关系,不需要统计逆序对;只有当右边区间比左边区间小的时候,需要统计逆序对个数,此时的逆序对个数为,左边区间还剩下的数的个数即mid-left+1
Java代码
java
class Solution {
public int reversePairs(int[] nums) {
int len = nums.length;
if (len < 2) {
return 0;
}
int[] copy = new int[len];
for (int i = 0; i < len; i++) {
copy[i] = nums[i];
}
int[] temp = new int[len];
return MergeSort(copy, 0, len - 1, temp);
}
private int MergeSort(int[] nums, int left, int right, int[] temp) {
// 当这个区间只剩一个元素时,这个子区间就不存在逆序数,返回0
if (left == right) {
return 0;
}
// int mid = (left+right)/2;
// 防止int溢出
int mid = left + (right - left) / 2;
int leftPairs = MergeSort(nums, left, mid, temp);
int rightPairs = MergeSort(nums, mid + 1, right, temp);
// 如果分出来的数组本身有序,则返回左边+右边
if (nums[mid] <= nums[mid + 1]) {
return leftPairs + rightPairs;
}
int crossPairs = mergeAndCount(nums, left, mid, right, temp);
return leftPairs + rightPairs + crossPairs;
}
private int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
for (int i = left; i <=right; i++) {
temp[i] = nums[i];
}
int i = left;
int j = mid + 1;
int count = 0;
for (int k = left; k <= right; k++) {
// 如果左边数组遍历完了,就直接把右边拷贝回去
if (i == mid + 1) {
nums[k] = temp[j];
j++;
} else if (j == right + 1) {
// 如果右边数组遍历完了,就直接把左边拷贝回去
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {
nums[k] = temp[i];
i++;
} else {
nums[k] = temp[j];
j++;
count += (mid - i + 1);
}
}
return count;
}
}
Python代码
暴力破解失败.....
python
class Solution:
def reversePairs(self, nums: List[int]) -> int:
i,j,count = 0,0,0
for i in range(len(nums)):
for j in range(1,len(nums)):
if(nums[j]<nums[i]):
count+=1
return count