题目: 给定整数数组 nums 和整数 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
普通解:
// sort()倒序排序
var findKthLargest = function(nums, k) {
return nums.sort((a,b) => b-a)[k - 1]
};
sort() 方法用于对数组的元素进行排序。
排序顺序可以是字母或数字,并按升序或降序。
默认排序顺序为按字母升序。
若 a 小于 b,在排序后的数组中 a 应该出现在 b 之前,则返回一个小于 0 的值。// 比较的是排序后的
若 a 等于b,则返回 0。
若 a 大于 b,则返回一个大于 0 的值。
简单点就是:比较函数两个参数a和b,返回a-b 升序,返回b-a 降序
问题在于用什么排序复杂度更低。以及剪枝,比如排到什么情况下就不用再担心处理了。 分析题目,最简单的方式就是将整个数组进行排序后输出第K大元素,但是使用排序算法后最好平均时间复杂度也是 O(nlogn),但是我们可以通过快排的思想进行优化,使平均时间复杂度变为O(n)。
根据快排partition思想,进行快速选择,时间复杂度能达到O(n)。
快速选择(荷兰国旗问题)
取TopK类型问题;
给定一个数组arr,和一个数num,请把小于等于num的数放在数 组的左边,大于num的数放在数组的右边;(荷兰国旗问题)
TopK类型问题:(荷兰国旗问题思路)
先说下Partition
function partition(arr, l, r) {
let pivot = arr[r] // 枢轴
let less = l - 1; // 维护小于枢轴的区域
let more = r; // 维护大于枢轴的区域;
// l相当于等于区域右侧指针,即当前位指针
// l指针右移,用于维护等于枢轴的区域
while(l < more) {
if(arr[l] < pivot) {
swap(arr, ++less, l++) // 小的数值要换到小数值区域指针后一位,也就是小数值区域扩展,l指针右移,处理下一项。
} else if(arr[l] > pivot) {
swap(arr, l, --more) // l指针停留,more指针前移
} else {
l++;
}
}
swap(arr, l, r) // l指针指向more指针指向相同
return [less+1, more] // 等于 pivot的数组索引
}
再说一下快排partition实现思路
function quickSort(arr, left, right) {
if(left < right) {
let pivot = partition(arr, left, right);
quickSort(arr, left, pivot[0] - 1);
quickSort(arr, pivot[1] + 1, right);
}
}
利用快排partition思路,取TopK
function findKthLargest(arr, k) {
const len = nums.length;
const targetIndex = len - k;
let left = 0, right = len - 1;
while(left < right) {
const index = partition(arr, left, right);
const [s, e] = index || [];
if(s <= targetIndex && targetIndex <= e) {
return arr[targetIndex]
} else if(targetIndex < s) {
left = s - 1; // 一点一点扩
} else {
right = e + 1; // 一点一点扩
}
}
}
引申问题: 给定一个数组arr,和一个数num,请把小于等于num的数放在数 组的左边,大于num的数放在数组的右边;
分析题干,不在意排序问题。
将小于等于某个值的item全部放到左边,大于的放到右边
需要一个X指针,来维护一个小于区域即可
代码实现:
var x = -1;
for ( var i=0; i<arr.length; i++){
arr[i] <= num ? arr[++x]交换arr[i] : null;
}