目录
一.归并排序
1.算法思想
归并排序采取分治法的思想。
第一步将一个数组按规模依次分为两部分 ,先左侧排序,再右侧排序,最后再通过辅助数组整体外排,将2个有序数列合并为最终有序。
主要是如何将2个有序数列合并。只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。
2.时间复杂度O(N*logN),额外空间复度O(N),算法稳定
3.实现代码
public static void mergeSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
mergeSort(arr, 0, arr.length - 1);
}
public static void mergeSort(int[] arr, int l, int r) {
if (l == r) {
return;
}
int mid = l + ((r - l) >> 1);
mergeSort(arr, l, mid);
mergeSort(arr, mid + 1, r);
merge(arr, l, mid, r);
}
public static void merge(int[] arr, int l, int m, int r) {
int[] help = new int[r - l + 1];
int i = 0;
int p1 = l;
int p2 = m + 1;
while (p1 <= m && p2 <= r) {
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
}
二.小和问题
1.问题描述
在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。例[1,3,4,2,5]
1左边比1小的数:没有
3左边比3小的数:1
4左边比4小的数:1,3
2左边比2小的数:1
5左边比5小的数:1,3,4,2
所以小和为1+1+3+1+1+3+4+2=16
2.思路分析
这是归并排序的过程,主要考虑在合并两个有序序列时,计算小和。
左边比当前数小的个数,相当于研究右边有多少比当前数大的。p1指向L,p2指向m+1,若前开始小于后开始,则前开始小于后面整个部分,小和为前面当前值*(后序列当前长度),否则没有小和。同时指针把较小数拷贝到辅助数组,较小数指针指针后移,最后再把多出的部分也添加到辅助数组。即最后要把两个有序序列合并到辅助数组并有序。
每次在合并前,先递归处理左半段,右半段。则左右有序,且左右的小和可以得到,再计算左右半段合并时的小和。
归并排序,是分治的思想。先递归分为两个部分,左右两部分分开之后,merge实现合并的过程。首先1,3产生小和1,辅助数组[1,3];然后25产生小和2,有序数组[2,5];13(为内层的有序数组返回来的),4产生小和1,3,有序数组[134];134,25产生小和1*2,3,4,有序数组[12345]。则小和=1+2+1+3+2+3+4=16。
指针移动的过程,比如p1为1比2小,则产生小和1*2,1进辅助数组,p1到3;3比2大,2进辅助数组,p2后移到5;3比5小,3进辅助数组,产生小和3,p1后移到4;同理4进辅助数组,产生小和4,5最后再进辅助数组。
此过程核心代码如下。
while (p1 <= m && p2 <= r) {
res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
3.实现代码
public class Code_12_SmallSum {
public static int smallSum(int[] arr) {
if (arr == null || arr.length < 2) {
return 0;
}
return mergeSort(arr, 0, arr.length - 1);
}
public static int mergeSort(int[] arr, int l, int r) {
if (l == r) {
return 0;
}
int mid = l + ((r - l) >> 1);
return mergeSort(arr, l, mid) + mergeSort(arr, mid + 1, r) + merge(arr, l, mid, r);
}
public static int merge(int[] arr, int l, int m, int r) {
int[] help = new int[r - l + 1];
int i = 0;
int p1 = l;
int p2 = m + 1;
int res = 0;
while (p1 <= m && p2 <= r) {
res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 0;
help[i++] = arr[p1] < arr[p2] ? arr[p1++] : arr[p2++];
}
while (p1 <= m) {
help[i++] = arr[p1++];
}
while (p2 <= r) {
help[i++] = arr[p2++];
}
for (i = 0; i < help.length; i++) {
arr[l + i] = help[i];
}
return res;
}