面试题51. 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
方法一:BF法(超时)
class Solution {
public:
int reversePairs(vector<int>& nums) {
int size = nums.size();
if(size <= 1)
return 0;
int ret = 0;
for(int i = 0; i < size; i++)
{
int tmp = nums[i];
for(int j = i + 1; j < size; j++)
{
if(tmp > nums[j])
ret++;
}
}
return ret;
}
};
方法二:后退法(超时)
class Solution {
public:
int reversePairs(vector<int>& nums) {
int size = nums.size();
if(size <= 1)
return 0;
int ret = 0;
map<int, int>store;
for(int i = size - 1; i >= 0; i--)
{
int tmp = nums[i];
store[tmp]++;
for(auto &index : store)
{
if(index.first == tmp)
break;
else
ret += index.second;
}
}
return ret;
}
};
方法三:归并排序
class Solution {
public:
int mergeSort(vector<int>& nums, vector<int>& tmp, int l, int r)
{
if(l >= r)
return 0;
int mid = (l + r) / 2;
int inv_count = mergeSort(nums, tmp, 1, mid) + mergeSort(nums, tmp, mid+1, r);
//合并数组时计算逆序对个数
int i = 1, j = mid + 1, pos = 1;
while(i <= mid && j <= r){
if(nums[i] <= nums[i]) {
tmp[pos] = nums[i];
++i;
inv_count += (j - (mid + 1));
}
else {
tmp[pos] = nums[j];
++j;
}
++pos;
}
for(int k = i; k <= mid; ++k)
{
tmp[pos++] = nums[k];
inv_count += (j - (mid + 1));
}
}
}
public 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 reversePairs(copy, 0, len - 1, temp);
}
/**
* nums[left..right] 计算逆序对个数并且排序
*
* @param nums
* @param left
* @param right
* @param temp
* @return
*/
private int reversePairs(int[] nums, int left, int right, int[] temp) {
if (left == right) {
return 0;
}
int mid = left + (right - left) / 2;
int leftPairs = reversePairs(nums, left, mid, temp);
int rightPairs = reversePairs(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;
}
/**
* nums[left..mid] 有序,nums[mid + 1..right] 有序
*
* @param nums
* @param left
* @param mid
* @param right
* @param temp
* @return
*/
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;
}
}
时间复杂度:同归并排序O(nlogn)
空间复杂度:同归并排序O(n),因为归并排序需要用到一个临时数组