剑指offer—数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
思路
取第一个数和它后面的数进行比较,若比后面的数大,则 count++,依次取第二个数…但是这样时间复杂度就是
O
(
N
2
)
O(N^2)
O(N2)(
(
n
−
1
)
+
(
n
−
2
)
+
.
.
.
+
1
=
n
(
n
−
1
)
/
2
=
O
(
N
2
)
(n-1) + (n-2) + ... + 1=n(n-1)/2=O(N^2)
(n−1)+(n−2)+...+1=n(n−1)/2=O(N2))
因为需要每一次都要比较两个数,在排序算法中也需要两两比较,只不过排序算法在比较后调动了数的位置,那么这两者有什么联系吗?
下图是归并排序的过程:
所以可以修改归并排序就能够求出数组中的逆序对的总数
代码
class Solution {
public:
//计数变量
int count = 0;
void merge(vector<int>& nums, int left, int mid, int right){
vector<int> temp;
int i = left, j = mid+1;
while(i <= mid && j <= right)
{
if(nums[i] <= nums[j]){
temp.push_back(nums[i]);
i++;
}else{
temp.push_back(nums[j]);
j++;
//在归并代码上增加的计数
count += mid-i+1;
}
}
while(i <= mid)
{
temp.push_back(nums[i]);
i++;
}
while(j <= right)
{
temp.push_back(nums[j]);
j++;
}
for(int k = 0; k < temp.size(); k++){
nums[left + k] = temp[k];
}
}
void mergeSort(vector<int>& nums, int left, int right){
//存在两个数才进行归并
if(left < right){
int mid = (left + right) >> 1;
mergeSort(nums, left, mid);
mergeSort(nums, mid+1, right);
merge(nums, left, mid, right);
}
}
int reversePairs(vector<int>& nums) {
mergeSort(nums, 0, nums.size()-1);
return count;
}
};