目录
- 原理
- 经典例题
- [912. 排序数组](https://leetcode.cn/problems/sort-an-array/description/)
- [LCR 170. 交易逆序对的总数](https://leetcode.cn/problems/shu-zu-zhong-de-ni-xu-dui-lcof/description/)
- 计算右侧小于当前元素的个数
- [493. 翻转对](https://leetcode.cn/problems/reverse-pairs/description/)
原理
归并算法的原理可以参考归并排序,归并排序算法不仅仅是使用该算法对数据进行排序,重要的是在归并的过程中解决某些问题,从而使一些原本时间复杂度较高的问题降到O(n*log2n)。
经典例题
912. 排序数组
给你一个整数数组 nums,请你将该数组升序排列。
你必须在 不使用任何内置函数 的情况下解决问题,时间复杂度为 O(nlog(n)),并且空间复杂度尽可能小。
这里可以使用归并排序解决:
class Solution {
public:void MySort(vector<int>& nums,int left,int right){if(left>=right){return;}int mid=(left+right)/2;MySort(nums,left,mid);MySort(nums,mid+1,right);int pos1=left;int pos2=mid+1;int end1=mid;int end2=right;vector<int> tmp;while(pos1<=end1&&pos2<=end2){if(nums[pos1]<nums[pos2]){tmp.push_back(nums[pos1]);++pos1;}else if(nums[pos1]>nums[pos2]){tmp.push_back(nums[pos2]);++pos2;}else{tmp.push_back(nums[pos1]);tmp.push_back(nums[pos2]);++pos1;++pos2;}}while(pos1<=end1){tmp.push_back(nums[pos1]);++pos1;}while(pos2<=end2){tmp.push_back(nums[pos2]);++pos2;}int i=left;for(auto e:tmp){nums[i++]=e;}}vector<int> sortArray(vector<int>& nums) {if(0==nums.size()){return nums;}MySort(nums,0,(int)nums.size()-1);return nums;}
};
LCR 170. 交易逆序对的总数
在股票交易中,如果前一天的股价高于后一天的股价,则可以认为存在一个「交易逆序对」。请设计一个程序,输入一段时间内的股票交易记录 record,返回其中存在的「交易逆序对」总数。
排降序,归并过程中计算逆序对
class Solution {
public:int GetAnswer(vector<int>& record,int left,int right){if(left>=right){return 0;}int mid=(left+right)/2;int count=GetAnswer(record,left,mid)+GetAnswer(record,mid+1,right);int pos1=left;int pos2=mid+1;int end1=mid;int end2=right;vector<int> tmp;while(pos1<=end1&&pos2<=end2){if(record[pos1]<record[pos2]){tmp.push_back(record[pos2++]);}else if(record[pos1]>record[pos2]){tmp.push_back(record[pos1++]);count+=end2-pos2+1;}else{tmp.push_back(record[pos2++]);}}while(pos1<=end1){tmp.push_back(record[pos1++]);}while(pos2<=end2){tmp.push_back(record[pos2++]);}for(auto e:tmp){record[left++]=e;}return count;}int reversePairs(vector<int>& record) {if(0==record.size()){return 0;}return GetAnswer(record,0,record.size()-1);}
};
计算右侧小于当前元素的个数
给你一个整数数组 nums ,按要求返回一个新数组 counts 。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
只需每个元素都绑定好数组下标,再进行归并排序即可,同时为了避免数组的开辟释放,可以提前开好足够的数组空间直接在该数组上操作即可,从而得到一定的优化。
class Solution {
public:void GetAnswer(vector<vector<int>>&nums,int left,int right){if(left>=right){return;}int mid=(left+right)/2;GetAnswer(nums,left,mid);GetAnswer(nums,mid+1,right);if(nums[left][0]==nums[mid][0]&&nums[mid][0]==nums[mid+1][0]&&nums[mid+1][0]==nums[right][0]){return;}int pos1=left;int pos2=mid+1;int end1=mid;int end2=right;vector<vector<int>> tmp;tmp.reserve(right-left+1);while(pos1<=end1&&pos2<=end2){if(nums[pos1][0]<nums[pos2][0]){tmp.push_back(nums[pos2++]);}else if(nums[pos1][0]>nums[pos2][0]){nums[pos1][1]+=end2-pos2+1;tmp.push_back(nums[pos1++]);}else{tmp.push_back(nums[pos2++]);}}while(pos1<=end1){tmp.push_back(nums[pos1++]);}for(auto& e:tmp){nums[left++]=e;}}vector<int> countSmaller(vector<int>& nums) {vector<vector<int>> tmp(nums.size(),vector<int>(3,0));int i=0;for(;i<nums.size();++i){tmp[i][0]=nums[i];tmp[i][2]=i;}GetAnswer(tmp,0,nums.size()-1);vector<int> ans(nums.size(),0);for(auto &e:tmp){ans[e[2]]=e[1];}return ans;}
};
493. 翻转对
给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
排降序归并
解法一:归并过程中,如果:
- nums [left]>2*nums[right]:left移入tmp1中,计算翻转对,++left
- nums[right] <= nums [left] <= 2*nums[right]:right移入tmp2中,++right
- nums [left] < nums[right]:right移入tmp1中,++right
解法二:
对左右两个部分,先计算完所有翻转对,再合并
class Solution {
public:int GetAnswer(vector<int>& record, int left, int right) {if (left >= right) {return 0;}int mid = (left + right) / 2;int count = GetAnswer(record, left, mid) + GetAnswer(record, mid + 1, right);int pos1 = left;int pos2 = mid + 1;int end1 = mid;int end2 = right;vector<int> tmp1;vector<int> tmp2;while (pos1 <= end1 && pos2 <= end2) {if (record[pos1] < record[pos2]) {if((long long int)record[pos1] >2* (long long int)record[pos2]){count += end2 - pos2 + 1;tmp2.push_back(record[pos1++]);}else{tmp1.push_back(record[pos2++]);}}else {if((long long int)record[pos1] >2* (long long int)record[pos2]){count += end2 - pos2 + 1;tmp1.push_back(record[pos1++]);}else{tmp2.push_back(record[pos2++]);}}}while (pos1 <= end1) {tmp1.push_back(record[pos1++]);}while (pos2 <= end2) {tmp1.push_back(record[pos2++]);}vector<int> tmp;for(pos1=0,pos2=0;pos1<tmp1.size()&&pos2<tmp2.size();){if(tmp1[pos1]>tmp2[pos2]){tmp.push_back(tmp1[pos1++]);}else if(tmp1[pos1]<tmp2[pos2]){tmp.push_back(tmp2[pos2++]);}else{tmp.push_back(tmp1[pos1++]);tmp.push_back(tmp2[pos2++]);}}while(pos1<tmp1.size()){tmp.push_back(tmp1[pos1++]);}while(pos2<tmp2.size()){tmp.push_back(tmp2[pos2++]);}for (auto e : tmp) {record[left++] = e;}return count;}int reversePairs(vector<int>& nums) {return GetAnswer(nums,0,nums.size()-1);}
};