学习算法:
归并排序:
1)整体是一个简单递归,左边排好序,右边排好序,让其整体有序。
2)时间复杂度 o(N*logN),额外空间复杂度o(N)
学习产出:
public class mergeSort {
public static void mergeSort(int[] arr) {
if (arr==null||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 m=l+((r-l)>>1);//求中间位置,>>1相当于除2
process(arr, l, m);
process(arr, m + 1, r);
merge(arr, l, m, 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+1+1+3+4+2=16
求一个数组的小和,可以理解为求在数组中右侧有几个数比当前数大?
public class SmallSum{
public static int smallSum(int[] arr) {
if (arr==null || arr.length<2){
return 0;
}
return process(arr,0,arr.length-1);
}
public static int process(int arr[],int l,int r){
if (r==l){
return 0;
}
int mid=l+((r-l)>>1);// >>1相当于除以2
return process(arr,l,mid)+process(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 p1=l;
int p2=m+1;
int i=0;
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;
}
}
类似题目:求逆序对,在一个数组中,左边的数如果比右边的数大,则这两个数构成一个逆序对,请有多少逆序对。
核心算法:
res+=arr[p1]>arr[p2]?(r-p2+1):0;
help[i++] = arr[p1] > arr[p2] ? arr[p1++] : arr[p2++];//由大到小排序