面试题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;elseret += 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),因为归并排序需要用到一个临时数组
