找到一个无序数组中第K小的数
样例
样例 1:
输入: [3, 4, 1, 2, 5], k = 3
输出: 3
样例 2:
输入: [1, 1, 1], k = 2
输出: 1
挑战
O(nlogn)的算法固然可行, 但如果你能 O(n) 解决, 那就非常棒了.
解题思路1:
快排的partition过程可定位到元素的位置,通过类似二分查找的定位方式找到第k小的数。
public class Solution {
/**
* @param k: An integer
* @param nums: An integer array
* @return: kth smallest element
*/
public int kthSmallest(int k, int[] nums) {
// write your code here
if(k > nums.length)
return -1;
int p = partition(nums, 0, nums.length-1);
while(p != k-1){
if(p < k-1)
p = partition(nums, p+1, nums.length-1);
else
p = partition(nums, 0, p-1);
}
return nums[p];
}
private int partition(int[] nums, int l, int r){
int v = nums[l];
int j = l;
for(int i=j+1; i<=r; i++){
if(nums[i] < v){
swap(nums, i, ++j);
}
}
swap(nums, l, j);
return j;
}
private void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
解题思路2:
优先队列。维护一个长度为k的最大堆,将nums中元素依次添加入优先队列,最后的队列头即为第k小元素。
public class Solution {
/**
* @param k: An integer
* @param nums: An integer array
* @return: kth smallest element
*/
public int kthSmallest(int k, int[] nums) {
// write your code here
if(k > nums.length)
return -1;
//队列头是最大值
PriorityQueue<Integer> queue = new PriorityQueue<>(11, Collections.reverseOrder());
//维护一个队列长度总为k,则队列头即为第k小元素
for(int i=0; i<nums.length; i++){
queue.offer(nums[i]);
if(queue.size() > k)
queue.poll();
}
return queue.poll();
}
}