PS:归并排序是一个套路迭代的过程,归并排序与数组中的逆序对和最小和问题三个基本上一样,只要理解了归并排序过程,其余两个过程自然可以理解。 直接上代码。
归并排序过程
class Solution {
public:
void mergeSort(vector<int> &arr) {
if (arr.size() == 0 || arr.size() < 2) return;
SortProcess(arr, 0, arr.size()-1);
}
//归并排序主体过程
void SortProcess(vector<int> &arr, int l, int r) {
if (r == l) return; // 递归停止
int mid = l + (r - l)/2;
SortProcess(arr, l, mid);
SortProcess(arr, mid + 1, r);
merge(arr, l, mid, r);
}
// 合并过程
void merge(vector<int> &arr, int l, int mid, int r) { // 这里需要 & ,不然会答案错误
vector<int> helper(r - l + 1); // 辅助数组用来存放排序后的数组
int i = 0;
// 两个指针
int p1 = l;
int p2 = mid + 1;
while (p1 <= mid && p2 <= r) {
if (arr[p1] < arr[p2]) {
helper[i++] = arr[p1++];
}
else {
helper[i++] = arr[p2++];
}
}
while (p1 <= mid) {// 注意这里可以等于
helper[i++] = arr[p1++];
}
while (p2 <= r) {
helper[i++] = arr[p2++];
}
// 将辅助数组元素位置拷贝会arr
for (int i = 0; i < helper.size(); i++) {
arr[l + i] = helper[i];
}
}
vector<int> generateRandomArr(int maxsize, int minsize, int length) {
vector<int> arr(length);
for (int i = 0; i < length; i++) {
arr[i] = rand() % (maxsize - minsize) + minsize + 1;
}
return arr;
}
};
数组中的逆序对
class Solution2 {
public:
int cnt = 0;
int reversePairs(vector<int> data) {
int n = data.size();
if (n != 0)
{
mergesort(data, 0, n - 1); //调用归并排序的分解函数
}
return cnt;
}
void mergesort(vector<int>& data, int start, int end) //分解
{
if (start < end ) // 递归终止条件
{
int mid = (start + end) >> 1;
mergesort(data, start, mid );
mergesort(data, mid+1,end);
merge(data, start, mid, end); //调用归并排序的合并排序函数
}
}
void merge(vector<int>& data, int start, int mid, int end)
{
vector<int> tmp(end-start+1); //tmp临时变量用来存储当前[start,end]段排序后的结果,然后再赋值给data
// 注意:一定要写大小,不然使用下标会出错
int i = start, j = mid + 1; //采用的是引用传递,所以修改的是原数组
int index = 0;
while (i <= mid&&j <= end)
{
if (data[i] > data[j])
{ // 此时产生逆序对
cnt = (cnt + mid - i + 1); // 有些题目需要取余数
tmp[index++] = data[j++]; // 这里也可以用tmp.push_back(data[j++]
}
else
tmp[index++] = data[i++];
} //tmp就是存data(start,end)区间内从小到大的存储起来
while (i <= mid) {
tmp[index++] = data[i++];
}
while (j <=end) {
tmp[index++] = data[j++];
}
for (int i = 0; i < tmp.size(); ++i)
{
data[start + i] = tmp[i];
}
}
};
最小和问题
class Solution3 {
public:
void Small_sum(vector<int> nums) {
if (nums.size() == 0) return;
sort_process(nums, 0, nums.size() - 1);
}
int sort_process(vector<int> &nums, int l, int r) {
// 递归停止
if (r == l) return;
int mid = l + (r - l) / 2;
return sort_process(nums, mid + 1, r)+
sort_process(nums, l, mid)+ merge(nums, l, mid, r);
}
int merge(vector<int> &arr, int l, int mid, int r) {
vector<int> helper(r - l + 1); // 辅助数组
int res = 0; // 产生小和数目
int i = 0;
int p1 = l;
int p2 = mid + 1;
while (p1 < mid && p2 <= r) {
if (arr[p1] < arr[p2]) {
res += (r - p2 + 1) * arr[p1];
helper[i++] = arr[p1++];
}
else {
helper[i++] = arr[p2++];
}
}
while (p1 <= mid) {
helper[i++] = arr[p1++];
}
while (p2 <= r) {
helper[i++] = arr[p2++];
}
// 将辅助数组元素位置拷贝会arr
for (int i = 0; i < helper.size(); i++) {
arr[l + i] = helper[i];
}
return res;
}
};