左神初级班2

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/weixin_42030357/article/details/102576263

例题:

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;
 	}
 	

猜你喜欢

转载自blog.csdn.net/weixin_42030357/article/details/102576263
今日推荐