【LeetCode】面试题51. 数组中的逆序对

2020.8.18更新

解题思路

参考数组中的逆序对官方题解
在这里插入图片描述
此题采用归并排序的思想,分,治(排序),合并——即是本题的重点,合并的时候进行计算
在这里插入图片描述

代码

class Solution {
public:
	int reversePairs(vector<int>& nums) {
		int n = nums.size();
		vector<int> tmp(n);
		return mergeSort(nums, tmp, 0, n - 1);
	}
	//归并排序的思想,在合并时,计算逆序对
	int mergeSort(vector<int>& nums, vector<int>& tmp, int left, int right) {
		if (left >= right) return 0;
		int mid = left + (right - left) / 2;
		int inv_count = mergeSort(nums, tmp, left, mid) + mergeSort(nums, tmp, mid + 1, right);
		//合并
		int i = left, j = mid + 1;
		for (int k = left; k <= right; k++) {
			if (j > right) { tmp[k] = nums[i++]; inv_count += j - (mid + 1); }//如果右边数组中已经取完,而左边没取完时计算贡献
			else if (i > mid) { tmp[k] = nums[j++]; }
			else if (nums[i] <= nums[j]) { tmp[k] = nums[i++]; inv_count += j - (mid + 1); }//nums[i]<=nums[j]时计算贡献,注意这里要为<=,否则如果两数相等,也会计算贡献
			else { tmp[k] = nums[j++]; }
		}
		for (int k = left; k <= right; k++) {
			nums[k] = tmp[k];
		}
		cout << "inv_count: " << inv_count << endl;
		return inv_count;
	}
};

解题思路

分治法:
采用的就是归并函数中的分治思想,该题与分治排序的不同点在于,在治的过程中进行逆序对的统计,逆序对的个数为
cnt += center - i + 1;
这也是在归并排序上要加的代码

代码

/*
思路:分治
通过分的方式,获得每个子区间,在合并每个子区间时计算每个子区间内部的逆序对个数
*/
#include<iostream>
#include <vector>
using std::vector;
class Solution {
	int cnt = 0;
public:
	int reversePairs(vector<int>& nums) {
		if (nums.size() < 2) return 0;//特判,size为0,1不可能出现逆序对
		vector<int> temps(nums.size());
		mergeSort(nums, temps, 0, nums.size() - 1);
		return cnt;
	}
	//归并排序
	void mergeSort(vector<int>& nums, vector<int>& temps, int left, int right) {
		if (left < right) {
			int center = left + (right - left) / 2;
			mergeSort(nums, temps, left, center);//左分
			mergeSort(nums, temps, center + 1, right);//右分
			merge(nums, temps, left, center, right);//治
		}
	}
	//合并
	void merge(vector<int>& nums, vector<int>& temp, int left, int center, int right) {

		int i = left, j = center + 1;
		for (int k = left; k <= right; k++) {
			if (i > center) {//左边的已经比较完,将右边的全部放到temp中
				temp[k] = nums[j++];
			}
			else if (j > right) {//右边的已经比较完,将左边的全部放到temp中
				temp[k] = nums[i++];
			}
			else if (nums[i] > nums[j]) {//左边大于右边,出现逆序对,
				temp[k] = nums[j++];//取右边数组值
				cnt += center - i + 1;//此处+1是因为center是等于right的,这里也是比归并排序多的一行代码
			}
			else//左边小于等于右边
			{
				temp[k] = nums[i++];//取左边数组值
			}
		}
		//将temp中的元素复制到nums中
		for (int k = left; k <= right; k++) {
			nums[k] = temp[k];
		}
	}

};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值