2.<tag-排序和归并排序巧妙解题>-剑指 Offer 51. 数组中的逆序对 + 补充题-计算数组的小和
剑指 Offer 51. 数组中的逆序对
[案例需求]
[思路分析]
- 这道题充分利用了归并排序的性质
- 视频题解
还有以下解法等待补充:
- 有序数组 (Sorted List)
- 归并排序 (Merge Sort)
- 树状数组 (Binary Indexed Tree)
- 线段树 (Segment Tree)
[代码实现]
class Solution {
int count = 0;
public int reversePairs(int[] nums) {
int len = nums.length;
mergeSort(nums, 0, len -1);
return count;
}
//分
public void mergeSort(int[] nums, int left, int right){
if(left >= right)return;
int mid = left + ((right - left) >> 1);
mergeSort(nums, left, mid);
mergeSort(nums, mid + 1, right);
sort(nums, left, mid, right);
}
//治
public void sort(int[] nums, int left, int mid, int right){
int[] res = new int[right - left + 1];
int index = 0;
int L = left, R = mid + 1;
// L--> mid, R-->right
while(L <= mid && R <= right){
if(nums[L] > nums[R]){
count += (mid - L + 1); //
res[index++] = nums[R++];
}else{
res[index++] = nums[L++];
}
}
while(L <= mid)res[index++] = nums[L++];
while(R <= right)res[index++] = nums[R++];
for(int i = 0; i < index; i++){
nums[i + left] = res[i];
}
}
}
补充题-计算数组的小和
[案例需求]
[思路分析] (cv得来的, 还需要深入
归并排序的应用,当归并过程中发现左边的数小于右边的数,即得到一组小和。如1 3 5 7 和 2 4 6 8,当左边遍历第一个数,有1 < 2,则1也小于2右边的所有数,即这组小和为1*4。
- 整个数组的小和=数组左半部分贡献的小和+数组右半部分贡献的小和+左右两部分之间贡献的小和
参考文章:
- https://mp.weixin.qq.com/s/rMsbcUf9ZPhvfRoyZGW6HA
- 点我
[代码实现]
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int len = in.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++) {
nums[i] = in.nextInt();
}
System.out.println(mergeSort(nums, 0, nums.length - 1, new int[nums.length]));
}
public static long mergeSort(int[] nums, int left, int right, int[] temp) {
if (left >= right) {
return 0;
}
int mid = left + (right - left) / 2;
long leftTempSum = mergeSort(nums, left, mid, temp);
long rightTempSum = mergeSort(nums, mid + 1, right, temp);
long curTempSum = merge(nums, left, mid, right, temp);
return leftTempSum + rightTempSum + curTempSum;
}
// 合并 nums[left:mid] nums[mid + 1:right] 这两段有序数组
public static long merge(int[] nums, int left, int mid, int right, int[] temp) {
int i = left, j = mid + 1, t = 0;
long tempSum = 0;
while (i <= mid && j <= right) {
if (nums[i] <= nums[j]) {
// 由于左右子数组均有序,所以 nums[i] 比 nums[j:right] 这些元素都要小,所以 nums[i] “产生” 的小和为 nums[i] * (right - j + 1)
tempSum += nums[i] * (right - j + 1);
temp[t++] = nums[i++];
} else {
temp[t++] = nums[j++];
}
}
while (i <= mid) {
temp[t++] = nums[i++];
}
while (j <= right) {
temp[t++] = nums[j++];
}
t = 0;//temp ***有 right - left + 1 个元素
while (left <= right) {
nums[left++] = temp[t++];
}
return tempSum;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律