【算法】【线性表】【数组】数组中的第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; } }
= =,超时了尴尬。。。。。
是不是我写的堆排序,不太优雅。
分类:
算法 / 数组
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· Obsidian + DeepSeek:免费 AI 助力你的知识管理,让你的笔记飞起来!
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
2023-03-25 【Spring MVC】请求处理过程
2023-03-25 【Spring MVC】创建过程