一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情。
前言
每天一道算法题,死磕算法
题目
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
分析
-
这个题目可能大家的第一反应是我排序一下,然后找到第 k 个最大的元素不就可以了么。是的,也没错,但我们有没有更简单的方法呢。答案是有的,就是在没有排序完成之前我们就找到第k个最大的元素
-
排序的算法哪个时间复杂度好一些呢,答案是快速排序、归并排序、堆排序,他们的时间复杂度都是O(nlogn),我们今天选用一下快速排序
-
然后我们使用快速排序+二分查找的模式来解决一下这个问题,二分查找也很好理解,就是如何等于我们想要找的数,就返回,没找到的话,继续缩小范围在循环在找
首先我们来回忆一下快速排序怎么写,具体的可以参考我的这篇文章绝对记得住的各种排序算法(中)
function partition(nums:number[], left, right):number{
let point = nums[left];
let i = left+1,j=right;
// 为了把所有的情况覆盖到,只有i>j的时候跳出循环
while(i<=j){
while(i<right && nums[i]<=point){
i++;
}
// 此 while 结束时恰好 nums[i] > pivot
while(j>left && nums[j]>point){
j--;
}
// 此 while 结束时恰好 nums[j] <= pivot
// 此时 [lo, i) <= pivot && (j, hi] > pivot
if(i >= j){
break;
}
[nums[i],nums[j]]=[nums[j],nums[i]];
}
// 此时j等于point
[nums[left],nums[j]] = [nums[j],nums[left]];
return j;
}
function quickSort(nums:number[], left, right){
if(left>right){
return;
}
let mid = partition(nums,left,right);
quickSort(nums,mid+1,right);
quickSort(nums,left,mid-1);
}
二分查找也复习一下
function search(nums: number[], target: number): number {
let left:number =0;
let right:number = nums.length-1;
while(left<=right){
let mid:number = left+Math.floor((right-left)/2);
if(target===nums[mid]){
return mid;
}else if(target<nums[mid]){
right = mid - 1;
}else if(target>nums[mid]){
left = left+1;
}
}
return -1;
};
题解
就是把上面两者合成一下
function partition(nums:number[], left, right):number{
let point = nums[left];
let i = left+1,j=right;
while(i<=j){
while(i<right && nums[i]<=point){
i++;
}
while(j>left && nums[j]>point){
j--;
}
if(i >= j){
break;
}
[nums[i],nums[j]]=[nums[j],nums[i]];
}
// 此时j等于point
[nums[left],nums[j]] = [nums[j],nums[left]];
return j;
}
function findKthLargest(nums: number[], k: number): number {
let n = nums.length;
let targetIndex = n - k;
let left = 0, right = nums.length-1;
while(left<=right){
let mid = partition(nums,left,right);
if(mid === targetIndex){
console.log(nums);
console.log(targetIndex);
return nums[mid];
}else if(targetIndex>mid){
left = mid +1;
}else{
right = mid-1;
}
}
return -1;
};