【算法】【线性表】【数组】数组中的第K个最大元素
1 题目
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2 输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4 输出: 4
提示:
1 <= k <= nums.length <= 105-104 <= nums[i] <= 104
2 解答
刚开始我这么想的,直接快速排序:
class Solution { public int findKthLargest(int[] nums, int k) { // 直接点 直接排序 排完直接返回 nums[k] quickSort(nums, 0, nums.length - 1); return nums[k - 1]; } public void quickSort(int[] nums, int start, int end) { if (start > end) { return; } int leftIndex = start; int rightIndex = end; int temp = nums[leftIndex]; while (leftIndex < rightIndex) { while (leftIndex < rightIndex && nums[rightIndex] <= temp) { rightIndex--; } while (leftIndex < rightIndex && nums[leftIndex] >= temp) { leftIndex++; } if (leftIndex < rightIndex) { nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex]; nums[rightIndex] = nums[leftIndex] ^ nums[rightIndex]; nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex]; } } nums[start] = nums[leftIndex]; nums[leftIndex] = temp; // 递归 quickSort(nums, start, rightIndex - 1); quickSort(nums, rightIndex + 1, end); } }
可是超时了,看来人家并不想我这么直接:

那么我们改一下快速排序,基于快速排序的特点是先找位置,然后再排位置的左边和右边,因为要找第 K 个,也就是说我没必要把所有的都排好,当我排到第K 个的时候,就可以停了,那我主要改了两个地方(下边有注释的两个地方):
class Solution { public int findKthLargest(int[] nums, int k) { // 直接点 直接排序 排完直接返回 nums[k] quickSort(nums, 0, nums.length - 1, k - 1); return nums[k - 1]; } public void quickSort(int[] nums, int start, int end, int target) { if (start > end) { return; } int leftIndex = start; int rightIndex = end; int temp = nums[leftIndex]; while (leftIndex < rightIndex) { while (leftIndex < rightIndex && nums[rightIndex] <= temp) { rightIndex--; } while (leftIndex < rightIndex && nums[leftIndex] >= temp) { leftIndex++; } if (leftIndex < rightIndex) { nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex]; nums[rightIndex] = nums[leftIndex] ^ nums[rightIndex]; nums[leftIndex] = nums[leftIndex] ^ nums[rightIndex]; } } nums[start] = nums[leftIndex]; nums[leftIndex] = temp; // 如果中间元素的位置就刚好等于第 K 个了 说明已经找到了,就不需要排序别的了 if (leftIndex == target) { return; } // 递归 // 根据 target 和 rightIndex 的大小来判断是排序左边还是右边 if (rightIndex >= target) { quickSort(nums, start, rightIndex - 1, target); } else { quickSort(nums, rightIndex + 1, end, target); } } }

哈哈哈,通过了,这个时间貌似有点拉跨啊,排到最后一名了都。对这种 TopK的问题,堆排序我再试试:
class Solution { public int findKthLargest(int[] nums, int k) { // 调整 k 次 for(int i = 0; i < k; i++) { // 先构造最大堆 adjustHead(nums, nums.length - i); // 然后交换 swap(nums, 0, nums.length - i - 1); } return nums[nums.length - k]; } /** * 调整堆 * @param arr * @param length */ public void adjustHead(int[] arr, int length) { // 从第一个非叶子节点开始 for (int i = length / 2 - 1; i >= 0; i--) { // 左右选一个最大的 int maxChildIndex = 2 * i + 1; if (maxChildIndex + 1 < length && arr[maxChildIndex + 1] > arr[maxChildIndex]) { maxChildIndex = maxChildIndex + 1; } // 如果儿子比爸爸大,那么就要交换 交换完继续向下调整 if (arr[i] < arr[maxChildIndex]) { swap(arr, i, maxChildIndex); int sub = 2 * maxChildIndex + 1; while (sub < length) { if (arr[sub] > arr[maxChildIndex]) { swap(arr, sub, maxChildIndex); sub = 2 * sub + 1; continue; } if (sub + 1 >= length || arr[sub + 1] <= arr[maxChildIndex]) { break; } swap(arr, sub + 1, maxChildIndex); sub = 2 * sub + 1; } } } } public void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } }
= =,超时了尴尬。。。。。

是不是我写的堆排序,不太优雅。

浙公网安备 33010602011771号