题目描述:
在未排序的数组中找到第 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个最大的元素。
这里顺便回顾一下排序算法,好久没写过了。
第一种解法:冒泡排序
代码实现:
class Solution {
public int findKthLargest(int[] nums, int k) {
for (int i = 0; i < nums.length; i++) {
boolean flag = true;
for (int j = nums.length - 1; j > i; j--) {
if (nums[j] < nums[j - 1]) {
exchange(j, j - 1, nums);
flag = false;
}
}
//flag为true---->两个相邻的数之间没有做交换---->任意一个前一个数小于后一个数---->已经完成排序的
if (flag) {
break;
}
}
// System.out.println(Arrays.toString(nums));
return nums[nums.length - k];
}
private static void exchange(int i, int j, int[] nums) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
第二种解法:选择排序
class Solution {
public int findKthLargest(int[] nums, int k) {
for (int i = 0; i < nums.length - 1; i++) {
//最小值的索引
int minIndex = i;
//找出最小值的索引
for (int j = i + 1; j < nums.length; j++) {
if (nums[j] < nums[minIndex]) {
minIndex = j;
}
}
if (minIndex != i) {
exchange(i, minIndex, nums);
}
}
return nums[nums.length - k];
}
private static void exchange(int i, int j, int[] nums) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
第三种解法:插入排序
class Solution {
public int findKthLargest(int[] nums, int k) {
for (int i = 0; i < nums.length-1; i++) {
for (int j = i + 1; j > 0; j--) {
if (nums[j] < nums[j - 1]) {
exchange(j, j - 1, nums);
} else {
break;
}
}
}
return nums[nums.length - k];
}
private static void exchange(int i, int j, int[] nums) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
第四种解法:希尔排序
class Solution {
public int findKthLargest(int[] nums, int k) {
int incre = nums.length;
while (true) {
incre = incre / 2;
//根据增量分为若干子序列
for (int m = 0; m < incre; m++) {
//类似于插入排序,只不过这里的i值每次是加增量的长度,而不是1
for (int i = m + incre; i < nums.length; i += incre) {
//这里的j也是每次减去增量的长度
for (int j = i; j > m; j -= incre) {
if (nums[j] < nums[j - incre]) {
exchange(j, j - incre, nums);
} else {
break;
}
}
}
}
if (incre <= 1) {
break;
}
}
return nums[nums.length - k];
}
private static void exchange(int i, int j, int[] nums) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
希尔排序的运行时间相比上边的减少了好多
执行用时 : 9 ms, 在Kth Largest Element in an Array的Java提交中击败了69.01% 的用户
内存消耗 : 39.2 MB, 在Kth Largest Element in an Array的Java提交中击败了61.64% 的用户
第五种解法:快速排序
class Solution {
public int findKthLargest(int[] nums, int k) {
quickSort(nums, 0, nums.length - 1);
return nums[nums.length - k];
}
private static void quickSort(int[] nums, int low, int high) {
if (low >= high) return;
int i = low;
int j = high;
int key = nums[low];
while (i < j) {
//从右往左找比key小的数
while (i < j && nums[j] >= key) {
j--;
}
//找到后,右边指针停下来,将找到这个数据给左边指针指的位置,然后开始从左往右找
if (i < j) {
nums[i] = nums[j];
i++;
}
//从左往右找比key大的
while (i < j && nums[i] < key) {
i++;
}
//找到后,左边指针停下来,将这个大的数据给右边指针指的
if (i < j) {
nums[j] = nums[i];
j--;
}
}
//i==j,此时这个位置就是key的位置,key左边的数据比key小,key右边的数据比key大
nums[i] = key;
//根据key的值所在的位置,将要排序的数分为两部分,一部分比key小,一部分比key大
quickSort(nums, low, i - 1);
quickSort(nums, i + 1, high);
}
}
key值的选取可以有多种形式,例如中间数或者随机数,分别会对算法的复杂度产生不同的影响。
第六种解法:归并排序
代码:
class Solution {
public int findKthLargest(int[] nums, int k) {
int first = 0;
int last = nums.length - 1;
int[] temp = new int[nums.length];
merge_sort(nums, first, last, temp);
// System.out.println(Arrays.toString(nums));
return nums[nums.length - k];
}
private static void merge_sort(int[] a, int first, int last, int[] temp) {
if (first < last) {
int middle = (first + last) / 2;
merge_sort(a, first, middle, temp);
merge_sort(a, middle + 1, last, temp);
mergeArray(a, first, middle, last, temp);
}
}
//合并:将两个序列a[first-->middle],a[middle+1-->end]合并到temp中
private static void mergeArray(int a[], int first, int middle, int end, int temp[]) {
int i = first;
int m = middle;
int j = middle + 1;
int n = end;
int k = 0;
while (i <= m && j <= n) {
if (a[i] <= a[j]) {
temp[k] = a[i];
k++;
i++;
} else {
temp[k] = a[j];
k++;
j++;
}
}
while (i <= m) {
temp[k] = a[i];
k++;
i++;
}
while (j <= n) {
temp[k] = a[j];
k++;
j++;
}
for (int ii = 0; ii < k; ii++) {
a[first + ii] = temp[ii];
}
}
}
速度越来越快了!!
执行用时 : 4 ms, 在Kth Largest Element in an Array的Java提交中击败了95.29% 的用户
内存消耗 : 35.6 MB, 在Kth Largest Element in an Array的Java提交中击败了99.11% 的用户
第七种解法:堆排序
代码:
class Solution {
public int findKthLargest(int[] nums, int k) {
MinHeap_Sort(nums, nums.length);
// System.out.println(Arrays.toString(nums));
return nums[k-1];
}
private static void MinHeap_Sort(int a[], int n) {
int temp = 0;
MakeMinHeap(a, n);
for (int i = n - 1; i > 0; i--) {
temp = a[0];
a[0] = a[i];
a[i] = temp;
MinHeapFixdown(a, 0, i);
}
}
//构建最小堆
private static void MakeMinHeap(int a[], int n) {
for (int i = (n - 1) / 2; i >= 0; i--) {
MinHeapFixdown(a, i, n);
}
}
//从i节点开始调整,n为节点总数
//从0开始计算 i节点的子节点为 2*i+1,2*i+2
private static void MinHeapFixdown(int a[], int i, int n) {
//i节点的左孩子节点
int j = 2 * i + 1;
int temp = 0;
while (j < n) {
if (j + 1 < n && a[j + 1] < a[j]) {
j++;
}
if (a[i] <= a[j]) {
break;
}
//较大的节点下移
temp = a[i];
a[i] = a[j];
a[j] = temp;
i = j;
j = 2 * i + 1;
}
}
}
执行用时 : 5 ms, 在Kth Largest Element in an Array的Java提交中击败了89.53% 的用户
内存消耗 : 36.5 MB, 在Kth Largest Element in an Array的Java提交中击败了95.61% 的用户