整体是递归分治的思想:左边排好序 + 右边排好序 + merge让整体有序。一般我们会暴力破解O(N²)的算法,如果进一步优化:就是可以利用上次计算的结果,不重复计算,不回退 这样的方案。
归并排序算法
package B2_lx.mytx.class04;import java.util.Arrays;/*** @title: Algorithm* @description: 递归* @author:* @date: 2022/07/03 05:02*/public class Code01_MergeSort {public static void mergeSort(int[] arr){if (null ==arr || arr.length<2){return;}process(arr,0, arr.length-1);}public static void process(int[] arr,int L, int R){if (L == R){return;}int mid = L + ((R - L) >>1);process(arr,L,mid);process(arr,mid+1,R);merge(arr,L,R,mid);}public static void merge(int[] arr, int L, int R, int M){int[] help = new int[R-L+1];int i = 0;int p1 = L;int p2 = M + 1;while (p1 <=M && p2 <= R){if (arr[p1] <= arr[p2]){help[i] = arr[p1];i++;p1++;}else {help[i] = arr[p2];i++;p2++;}//help[i++] = arr[p1] >= arr[p2] ? arr[p1++] : arr[p2++];}while (p1 <= M){help[i] = arr[p1];i++;p1++;}while (p2 <= R){help[i] = arr[p2];i++;p2++;}for (int j = 0; j < help.length; j++) {arr[L + j] = help[j];}System.out.println(Arrays.toString(help));}public static void main(String[] args) {int[] arr = new int[]{8,3,5,2,7,4,9,1,6};mergeSort(arr);System.out.println(Arrays.toString(arr));}}
小和问题
在一个数组中,一个数左边比它小的数的总和,叫数的小和,所有数的小和累加起来,叫数组小和。求数组小和。 例子: [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
package B2_lx.mytx.class04;/*** @title: Algorithm* @description: 小和问题* @author: 北京小桔汇金网络科技有限公司* @date: 2022/07/06 23:23*/public class Code02_SmallSum {public static Integer process(Integer[] arr,int L,int R){if (L == R){return 0;}int mid = L + ((R - L)>>1);return process(arr,L,mid) +process(arr,mid +1, R) +merge(arr,L,R,mid);}public static Integer merge(Integer[] arr,int L,int R,int mid){Integer[] help = new Integer[R-L+1];int i = 0;int p1 = L;int p2 = mid +1;int result = 0;while (p1 <= mid && p2 <=R){result += arr[p1] < arr[p2] ? arr[p1] * (R-p2+1) :0;help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];//if (arr[p1] <= arr[p2]){// help[i] = arr[p1];// i++;// p1++;//}else {// help[i] = arr[p2];// i++;// p2++;//}}while (p1 <=mid){help[i++] = arr[p1++];}while ((p2 <=R)){help[i++] = arr[p2++];}for (i = 0; i < help.length; i++) {arr[L+i] = help[i];}return result;}public static void main(String[] args) {Integer[] arr = new Integer[]{1,3,4,2,5};System.out.println(process(arr,0,4));;}}
逆序对问题
在一个数组中, 任何一个前面的数a,和任何一个后面的数b, 如果(a,b)是降序的,就称为逆序对 返回数组中所有的逆序对
package B2_lx.mytx.class04;/*** @title: Algorithm* @description: 逆序对* @author: 北京小桔汇金网络科技有限公司* @date: 2022/07/07 15:44*/public class Code03_ReversePair {public static int reversePair(int[] arr){if (null == arr || arr.length <2){return 0;}return process(arr,0,arr.length -1);}public static int process(int[] arr, int L, int R){if (L == R){return 0;}int mid = L + ((R - L)>>1);return process(arr,L,mid) + process(arr,mid+1, R) + merge(arr,L,mid,R);}public static int merge(int[] arr,int L, int mid, int R){int[] help = new int[R -L +1];int i = help.length -1;int p1 = mid;int p2 = R;int result = 0;while (p1 >=L && p2 > mid){/*if (arr[p1] <= arr[p2]){help[i] = arr[p2];i--;p2 --;} else {help[i] = arr[p1];i--;p1 --;result = result + (p2 - mid);}*/result += arr[p1] > arr[p2] ? (p2 - mid) : 0;help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];}while (p1>=L){help[i--] = arr[p1--];}while (p2 >mid){help[i--] = arr[p2--];}for ( i = 0; i < help.length; i++) {arr[L+i] = help[i];}return result;}public static void main(String[] args) {int[] arr = new int[]{3,5,1,2,6,4,9,7};System.out.println(reversePair(arr));}}
大于两倍问题
求任何一个位置上的子数组(可以利用前缀和) 在一个数组中, 对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数 比如:[3,1,7,0,2] 3的后面有:1,0 1的后面有:0 7的后面有:0,2 0的后面没有 2的后面没有 所以总共有5个
package B2_lx.mytx.class04;
/**
* @title: Algorithm
* @description: 在一个数组中,对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数
* @author: 北京小桔汇金网络科技有限公司
* @date: 2022/07/08 09:55
*/
public class Code04_BiggerThanRightTwice {
public static Integer biggerThanRightTwice(int[] arr){
if (null == arr || arr.length<2){
return 0;
}
return process(arr,0,arr.length-1);
}
public static int process(int[] arr,int l, int r){
if (l == r ){
return 0;
}
int m = l + ((r-l)>>1);
return process(arr,l,m) + process(arr,m+1,r) + merge(arr,l,r,m);
}
public static int merge(int[] arr,int l,int r,int m){
//分成2步,先merge计算出 右边有几个数,乘2后仍然小于 它。
int winR = m+1;
int result = 0;
for (int i = l; i<=m; i++){
while (winR <=r && arr[i] > (arr[winR] * 2)){
winR ++;
}
result += winR - (m +1);
}
// 这里无需merge排序,不需要归并算法的排序操作
/*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 (int j = 0; j< help.length; j++){
arr[l+j] = help[j];
}*/
return result;
}
public static void main(String[] args) {
int[] arr = new int[]{3,1,7,0,2};
System.out.println(biggerThanRightTwice(arr));
}
}
