数据结构与算法
P4 认识O(Nlog N)的排序
递归方法
mid=(L+R)/2 可能会溢出
mid=L+(R-L)/2 >>> mid=L+(R-L)>>1[二进制右移等价于相除,左移等价于相乘]
public static int process(int[] arr, int L,int R){
if(L==R){
return arr[L];
}
int mid=L+((R-L)>>1);//中点
int leftMax=process(arr,L,mid);
int rightMax=process(arr,mid+1,R);
return Math.max(leftMax,rightMax);
}
Master 公式:
T
(
N
)
=
a
∗
T
(
N
b
)
+
O
(
N
d
)
T(N)=a*T(\frac{N}{b})+O(N^d)
T(N)=a∗T(bN)+O(Nd)
a:子问题次数 N/b:子问题规模
T(N)=2*T(N/2)+O(1)
满足master公式的递归,若
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,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];
}
}
T(N)=2T(N/2)+O(N)
O(N*log N)
题目二 归并排序的扩展
小和问题:在一个数组中,每一个数左边比当前数小的数累加起来,叫做这个数组的小和。求一个数组的小和。
和排序问题的差别:
小和问题相等时拷贝右组小和
排序问题都可
public static int smallSum(int[] arr){
if(arr==null || arr.length<2){
return 0;
}
return process(arr,0,arr.length-1);
}
arr[L..R]既要排好序,也要求小和
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 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;
}
逆序对问题:在一个数组中,左边的数如果比右边的数大,则两个数构成一个逆序对,打印所有逆序对
题目六 荷兰国旗问题
- 给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组右边。要求额外空间复杂度O(1),时间复杂度O(N)。
- 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组中间,大于num的数放在数组右边。要求额外空间复杂度O(1),时间复杂度O(N)。
1的思路:1)[i]<=num,[i]和<=区的下一个数交换,<=区右扩,i++
2)[i]>num,i++。
2的思路:1)[i]<num,[i]和<区下一个交换,<区右扩,i++
2)[i]==num,i++
3)[i]>num.[i]和>区前一个交换,>区左扩,i原地不变。
快排1.0 【<5|>5|5】
快排2.0 [<5|==5|>5|5]
快排3.0 [<5|==5|>5|5],5是随机选的
public static void quickSort(int[] arr,int L,int R){
if(L<R){
swap(arr,L+(int)(Math.random()*(R-L+1)),R);
int[] p=partition(arr,L,R);
quickSort(arr,L,p[0]-1);//<区
quickSort(arr,p[1]+1,R);//>区
}
}
public static int[] partition(int[] arr,int L,int R){
int less=L-1;//<区右边界
int more=R;//>区左边界
while(L<more){
if(arr[L]<arr[R]){
swap(arr,++less,L++);
}else if(arr[L]>arr[R]){
swap(arr,--more,L);
}else{
L++;
}
}
swap(arr,more,R);
return new int[] {less+1,more};
}