目录
912. 排序数组
解析
题解
LCR 170. 交易逆序对的总数(数组中的逆序对)
解析
题解
315. 计算右侧小于当前元素的个数
解析
题解
493. 翻转对
解析
题解
912. 排序数组
912. 排序数组
解析
题解
1.局部临时数组
class Solution {
public:
vector<int> sortArray(vector<int>& nums) {
// 49.专题八_分治-归并_归并排序_C++
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int left, int right)
{
if (left >= right) return;
// 1.选择中间点划分区间
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2.把左右区间排序
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
// 3.合并两个有序数组
vector<int> tmp(right - left + 1);
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid && cur2 <= right)
tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
// 4.处理没有遍历完的数组
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
// 5.还原
for (int i = left; i <= right; ++i)
nums[i] = tmp[i - left];
}
};
2.全局临时数组
class Solution {
public:
vector<int> tmp;
vector<int> sortArray(vector<int>& nums) {
// 49.专题八_分治-归并_归并排序_C++
tmp.resize(nums.size());
mergeSort(nums, 0, nums.size() - 1);
return nums;
}
void mergeSort(vector<int>& nums, int left, int right)
{
if (left >= right) return;
// 1.选择中间点划分区间
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2.把左右区间排序
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
// 3.合并两个有序数组
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid && cur2 <= right)
tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
// 4.处理没有遍历完的数组
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
// 5.还原
for (int i = left; i <= right; ++i)
nums[i] = tmp[i - left];
}
};
LCR 170. 交易逆序对的总数(数组中的逆序对)
LCR 170. 交易逆序对的总数
解析
题解
1.升序
class Solution {
public:
int tmp[50001] = {0};
int reversePairs(vector<int>& record) {
// 50.专题八_分治-归并_数组中的逆序对_C++
// 1.升序
return mergeSort(record, 0, record.size() - 1);
}
int mergeSort(vector<int>& record, int left, int right)
{
if (left >= right) return 0;
int ret = 0;
// 1. 找中间点, 将数组分成两部分
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2. 左边的个数 + 排序 + 右边的个数 + 排序
ret += mergeSort(record, left, mid);
ret += mergeSort(record, mid + 1, right);
// 3. 一左一右的个数
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid && cur2 <= right)
{
if (record[cur1] <= record[cur2])
{
tmp[i++] = record[cur1++];
}
else
{
ret += mid - cur1 + 1;
tmp[i++] = record[cur2++];
}
}
// 4.处理一下排序
while(cur1 <= mid) tmp[i++] = record[cur1++];
while(cur2 <= right) tmp[i++] = record[cur2++];
for(int j = left; j <= right; ++j)
record[j] = tmp[j - left];
return ret;
}
};
2.降序
class Solution {
public:
int tmp[50001] = {0};
int reversePairs(vector<int>& record) {
// 50.专题八_分治-归并_数组中的逆序对_C++
// 1.降序
return mergeSort(record, 0, record.size() - 1);
}
int mergeSort(vector<int>& record, int left, int right)
{
if (left >= right) return 0;
int ret = 0;
// 1. 找中间点, 将数组分成两部分
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2. 左边的个数 + 排序 + 右边的个数 + 排序
ret += mergeSort(record, left, mid);
ret += mergeSort(record, mid + 1, right);
// 3. 一左一右的个数
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid && cur2 <= right)
{
if (record[cur1] <= record[cur2])
{
tmp[i++] = record[cur2++];
}
else
{
ret += right - cur2 + 1;
tmp[i++] = record[cur1++];
}
}
// 4.处理一下排序
while(cur1 <= mid) tmp[i++] = record[cur1++];
while(cur2 <= right) tmp[i++] = record[cur2++];
for(int j = left; j <= right; ++j)
record[j] = tmp[j - left];
return ret;
}
};
315. 计算右侧小于当前元素的个数
315. 计算右侧小于当前元素的个数
解析
题解
class Solution {
public:
vector<int> ret;
vector<int> index; // 记录 nums 中当前元素的原始下标
int tmpNums[500010];
int tmpIndex[500010];
vector<int> countSmaller(vector<int>& nums) {
// 51.专题八_分治-归并_计算右侧小于当前元素的个数_C++
int n = nums.size();
ret.resize(n);
index.resize(n);
// 初始一下 index 数组
for (int i = 0; i < n; ++i)
index[i] = i;
mergeSort(nums, 0, n - 1);
return ret;
}
void mergeSort(vector<int>& nums, int left, int right)
{
if (left >= right) return;
// 1.根据中间元素,划分区间
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2.先处理左右两部分
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
// 3.处理一左一右的情况
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid && cur2 <= right)
{
if (nums[cur1] <= nums[cur2])
{
tmpNums[i] = nums[cur2];
tmpIndex[i++] = index[cur2++];
}
else
{
ret[index[cur1]] += right - cur2 + 1; // 重点
tmpNums[i] = nums[cur1];
tmpIndex[i++] = index[cur1++];
}
}
// 4.处理剩下的排序过程
while(cur1 <= mid)
{
tmpNums[i] = nums[cur1];
tmpIndex[i++] = index[cur1++];
}
while(cur2 <= right)
{
tmpNums[i] = nums[cur2];
tmpIndex[i++] = index[cur2++];
}
for (int j = left; j <= right; ++j)
{
nums[j] = tmpNums[j - left];
index[j] = tmpIndex[j - left];
}
}
};
493. 翻转对
493. 翻转对
解析
题解
1.降序
class Solution {
public:
int tmp[50010];
int reversePairs(vector<int>& nums) {
// 52.专题八_分治-归并_翻转对_C++
// 1.降序
return mergeSort(nums, 0, nums.size() - 1);
}
int mergeSort(vector<int>& nums, int left, int right)
{
if (left >= right) return 0;
int ret = 0;
// 1.先根据中间元素划分区间
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2.先计算左右两侧的翻转对
ret += mergeSort(nums, left, mid);
ret += mergeSort(nums, mid + 1, right);
// 3.先计算翻转对的数量
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur1 <= mid)
{
while(cur2 <= right && nums[cur2] >= nums[cur1] / 2.0) cur2++;
if (cur2 > right) break;
ret += right - cur2 + 1;
cur1++;
}
// 4.合并两个有序数组
cur1 = left, cur2 = mid + 1;
while(cur1 <= mid && cur2 <= right)
tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur2++] : nums[cur1++];
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
for (int j = left; j <= right; ++j)
nums[j] = tmp[j - left];
return ret;
}
};
2.升序
class Solution {
public:
int tmp[50010];
int reversePairs(vector<int>& nums) {
// 52.专题八_分治-归并_翻转对_C++
// 1.升序
return mergeSort(nums, 0, nums.size() - 1);
}
int mergeSort(vector<int>& nums, int left, int right)
{
if (left >= right) return 0;
int ret = 0;
// 1.先根据中间元素划分区间
int mid = (right - left) / 2 + left;
// [left, mid] [mid + 1, right]
// 2.先计算左右两侧的翻转对
ret += mergeSort(nums, left, mid);
ret += mergeSort(nums, mid + 1, right);
// 3.先计算翻转对的数量
int cur1 = left, cur2 = mid + 1, i = 0;
while(cur2 <= right)
{
while(cur1 <= mid && nums[cur2] >= nums[cur1] / 2.0) cur1++;
if (cur1 > mid) break;
ret += mid - cur1 + 1;
cur2++;
}
// 4.合并两个有序数组
cur1 = left, cur2 = mid + 1;
while(cur1 <= mid && cur2 <= right)
tmp[i++] = nums[cur1] <= nums[cur2] ? nums[cur1++] : nums[cur2++];
while(cur1 <= mid) tmp[i++] = nums[cur1++];
while(cur2 <= right) tmp[i++] = nums[cur2++];
for (int j = left; j <= right; ++j)
nums[j] = tmp[j - left];
return ret;
}
};