BFPRT(无序数组中找到第k大的数,或者第k小的数)时间复杂度O(N)(学习笔记)

  1. 分组
  2. 组内排序(每5个一组,组内排序,组间不排序)
  3. 中位数拿出组成N/5大小的新数组(new_arr)
  4. 递归调用bfprt(new_arr,new_arr.length/2);,拿到返回值num
  5. 根据num值划分左中右,来找是否命中第k小的数
public static int getMinKthByBFPRT(int[] arr,int k) {
		int[] copyArr=copyArray(arr);
		return bfprt(copyArr,0,copyArr.length-1,k-1);//要求第k大的,k是1...n,所以这里函数应该传入k-1大
	}
	
	
	public static int[] copyArray(int[] arr) {
		int[] res=new int[arr.length];
		for(int i=0;i<res.length;i++) {
			res[i]=arr[i];
		}
		return res;
	}
	
	public static int bfprt(int[] arr,int begin,int end,int i) {
		if(begin==end)
			return arr[begin];
		
		int pivot=medianOfMedians(arr,begin,end);//中位数组成的数组的中位数
		int[] pivotRange=partition(arr,begin,end,pivot);//根据pivot来划分“小于区域”,“等于区域”,“大于区域”,返回“等于区域”的范围
		
		if(i>=pivotRange[0]&&i<=pivotRange[1])
			return arr[i];//命中第i大的,直接返回第i大的数值
		else if(i<pivotRange[0])
			return bfprt(arr, begin, pivotRange[0]-1, i);
		else 
			return bfprt(arr, pivotRange[1]+1, end, i);
	}
	
	public static int medianOfMedians(int[] arr,int begin,int end) {
		int num=end-begin+1;
		int offset=num%5==0?0:1;
		//中位数组成的数组
		int[] mArr=new int[num%5+offset];
		for(int i=0;i<mArr.length;i++) {
			int beginI=begin+5*i;
			int endI=beginI+4;
			mArr[i]=getMedian(arr, beginI, Math.min(end, endI));
		}
		return bfprt(mArr, 0, mArr.length-1, mArr.length/2);//求中位数数组的中位数
	}
	
	public static int getMedian(int[] arr,int begin,int end) {
		insertionSort(arr, begin, end);
		int sum=begin+end;
		int mid=sum/2+sum%2;
		return arr[mid];
	}
	public static void insertionSort(int[] arr,int begin,int end) {
		for(int i=begin+1;i!=end+1;i++)
			for(int j=i;i!=begin;j--) {
				if(arr[j-1]>arr[j])
					swap(arr, j-1, j);
				else
					break;
			}
	}
	
	public static int[] partition(int[] arr,int begin,int end,int pivotValue) {
		int left=begin-1;
		int right=end-1;
		int cur=begin;
		while(cur!=right) {
			if(arr[cur]<pivotValue) {
				swap(arr, ++left, cur++);
			}
			else if(arr[cur]>pivotValue) {
				swap(arr, cur, --right);
			}
			else
				cur++;
		}
		int[] range=new int[2];
		range[0]=left+1;
		range[1]=right-1;
		return range;
	}
	
	public static void swap(int[] arr,int i,int j) {
		int tmp=arr[i];
		arr[i]=arr[j];
		arr[j]=tmp;
	}



  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值