215. 数组中的第K个最大元素 BFPRT最牛解法

举报
兔老大 发表于 2021/04/24 01:31:51 2021/04/24
1.9k+ 0 0
【摘要】 在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 示例 2: 输入: [3,2,3,1,2,4,5,5,6] 和 k = 4 输出: 4 说明: 你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。 思路:堆...

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

思路:堆、改进快排、BFPRT

解释链接


      public class Solution {
      /*
      //前k小
       public static int[] getMinKNumsByBFPRT(int[] arr, int k) {
       if (k < 1 || k > arr.length) {
       return arr;
       }
       int minKth = findKthLargest(arr, k);
       int[] res = new int[k];
       int index = 0;
       for (int i = 0; i != arr.length; i++) {
       if (arr[i] < minKth) {
       res[index++] = arr[i];
       }
       }
       for (; index != res.length; index++) {
       res[index] = minKth;
       }
       return res;
       }
       */
      //第k小
     	public static int findKthLargest(int[] arr, int K) {
     		int[] copyArr = copyArray(arr);
     		return select(copyArr, 0, copyArr.length - 1, arr.length-K);
      	}
     	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;
      	}
      //给定一个数组和范围,求第i小的数
     	public static int select(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);
     		if (i >= pivotRange[0] && i <= pivotRange[1]) {
     			return arr[i];
      		} else if (i < pivotRange[0]) {
     			return select(arr, begin, pivotRange[0] - 1, i);
      		} else {
     			return select(arr, pivotRange[1] + 1, end, i);
      		}
      	}
      //在begin end范围内进行操作
     	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 + i * 5;
     			int endI = beginI + 4;
      			mArr[i] = getMedian(arr, beginI, Math.min(end, endI));
      		}
     		return select(mArr, 0, mArr.length - 1, mArr.length / 2);
      //只不过i等于长度一半,用来求中位数
      	}
      //经典partition过程
     	public static int[] partition(int[] arr, int begin, int end, int pivotValue) {
     		int small = begin - 1;
     		int cur = begin;
     		int big = end + 1;
     		while (cur != big) {
     			if (arr[cur] < pivotValue) {
       swap(arr, ++small, cur++);
      			} else if (arr[cur] > pivotValue) {
       swap(arr, cur, --big);
      			} else {
       cur++;
      			}
      		}
     		int[] range = new int[2];
      		range[0] = small + 1;
      		range[1] = big - 1;
     		return range;
      	}
      //五个数排序,返回中位数
     	public static int getMedian(int[] arr, int begin, int end) {
      		insertionSort(arr, begin, end);
     		int sum = end + begin;
     		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; j != begin; j--) {
      if (arr[j - 1] > arr[j]) {
       swap(arr, j - 1, j);
       } else {
      break;
       }
      			}
      		}
      	}
      //交换值
     	public static void swap(int[] arr, int index1, int index2) {
     		int tmp = arr[index1];
      		arr[index1] = arr[index2];
      		arr[index2] = tmp;
      	}
      /*
      //打印
       public static void printArray(int[] arr) {
       for (int i = 0; i != arr.length; i++) {
       System.out.print(arr[i] + " ");
       }
       System.out.println();
       }
       */
      }
  
 

文章来源: fantianzuo.blog.csdn.net,作者:兔老大RabbitMQ,版权归原作者所有,如需转载,请联系作者。

原文链接:fantianzuo.blog.csdn.net/article/details/104079514

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。