例题:
1.
**思路:**1.其实可以转换成比当前数(curr)大的有几个(i)数,此时的小和就是i*curr;
2.然后利用归并排序来进行解决问题。
public class Code_12_smallSum{
public static int smallSum(int[] arr){
if(arr=null||arr.length<2){
return ;
}
return mergeSort(arr,0,arr.length-1);
}
public static int mergeSort(int[] arr,int l ,int r){
if(l==r){
return ;
}
int mid = l+(r-l)>>1 //这种写法是等价于 int mid=(l+r)/2;并且是防溢出的,同时位运算相对于算数运算较快。
return mergeSort(arr,l,mid)+mergeSort(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 mid =(l+r)/2;
int res = 0;
int p1=l;
int p2=mid+1;
//还是使用两个指针,然后相比较,较小的放入到临时数组中,同时指针向右移动,直到有一边的指针移出,然后将剩余的数组全部放入到临时数组中。
//注意:这里的res;比较两边的值,看右边的值,因为已经是排好序的了。如果左边的这个指针小于右边的指针,那么右边的所有的数都是小和数。需要全部加起来。
while(p1<=mid&&p2<=r){
res +=arr[p1]<arr[p2]?arr[p1]*(r-p2+1):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(int i=0;i<help.length;i++){
arr[l+i] =help[i];
}
}
}
2.
直接看问题2 ,然后问题1就是2的简化:
思路:
情况1:curr==num的时候直接跳下一个,不管他
情况2: curr<num:将curr与小于区域的下一个数进行交换,然后小于区域向前扩一个位置。curr++,less++;
情况3:curr>num: 将curr与大于区域的上一个数进行交换,然后大于区域向前扩一个位置,然后在判读(这里还需要判断)
当less和more撞上了,整个过程结束。
public static int[] partition(int[] arr,int l,int r,int num){
int less= l-1;
int more =r+1;
int curr=l;
while(curr<more){
if(arr[curr]<num){
swap(arr,++less,curr++); //先将小于区域的前一个位置与curr位置交换,然后当前位置后移一位。主语++i和i++之间的关系
}else if(arr[curr]>num){
swap(arr,--more,curr); //先将大于区域前的一个数与当前位置交换,但是当前位置不变进行判断
}else{
curr++;
}
}
return new int[] {less+1,more-1};
}
public static void swap(int[] arr,int i,int j){
int temp =arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
3.快速排序(用荷兰国旗问题改进)
思路:选取数组的最后一个为参照。小于区域在左边,等于区域在中间,大于区域在右边。然后返回的是等于区域的位置,然后根据等于区域的位置然后进行递归。(上面比较的时候用了一个index比较好理解,与下面的这种用l代替是一样的。)
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);//等于区域的位置,p中固定只有两个元素。
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; //因为我们选取的就是最后一个元素,作为比较,所以不参与。右边区域直接到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};
}
堆排序
思路:首先将数组形成一个大根堆,然后将堆顶的数和最后一个数,进行交换,然后调整位置,使剩余的也变成一个大根堆。
public static void heapSort(int[] arr){
if(arr==null||arr.length<2){
return;
}
for(int i=0;i<arr.length;i++){
heapInsert(arr,i);
}
int heapSize =arr.length;
swap(arr,0,--heapSize);
while(heapSize>0){
heapify(arr,index,heapSize);
swap(arr,0,--heapSize);
}
}
}
//当值变小之后,向下沉淀
public static void heapify(arr,int index,int heapSize ){
int left =index*2+1;
int largest= left+1<heapSize&&arr[left]<arr[left+1]?left+1:left;
largest=arr[index]>arr[largest]?index:largest;
if(larest==index){
break;
}
swap(arr,index,largest);
index =largest;
left =2*index+1;
}
//形成大跟堆
public static void heapInsert(int[] arr,int index){
if(arr[index]>arr[(index-1)/2]){
swap(arr,index,(index-1)/2);
index =(index-1)/2;
}