模板
快速排序作为一个经典的排序算法有着高效稳定的优势,快速排序的思路也非常简单。首先我们选取一个数作为基数,然后把所有比这个数小的数字放在左边,大的放在右边,然后再以这个数字为分割线,对左右两边的数组继续排序。 由此我们可以写出快速排序的经典模式(升序):
public void quickSort(int[] nums,int start,int end){
if(start >= end)
return;
int mid = partition(nums,start,end);
quickSort(nums,start,mid-1);
quickSort(nums,mid+1,end);
}
public int partition(int[] nums,int start,int end){
if(start >= end)
return start;
int tmp = nums[start];
int i = start;
int j = end;
while(i<j){
//注意这边要使用>=,
//使用>会导致两个数反复交换然后进入死循环
while(i<j && nums[j]>=tmp) j--;
nums[i] = nums[j];
while(i<j && nums[i]<=tmp) i++;
nums[j] = nums[i];
}
//此时i和j相等
nums[i] = tmp;
return i;
}
数组中第K个最大元素
题目:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/
题目大意:在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 分析:这道题的一种比较快速的解法就是进行快速排序,一旦快速排序后返回的位置是k-1,那说明左边k个数已经是最大的了,直接返回。
代码:
class Solution {
public int findKthLargest(int[] nums, int k) {
if(nums == null || nums.length == 0)
return 0;
if(k>nums.length)
k = nums.length;
quickSort(nums,0,nums.length-1, k);
return nums[k-1];
}
public void quickSort(int[] nums,int start,int end,int k){
if(start >= end)
return;
int mid = partition(nums,start,end);
if(mid == k-1)
return;
else if(mid > k-1)
quickSort(nums,start,mid-1, k);
else
quickSort(nums,mid+1,end, k);
}
public int partition(int[] nums,int start,int end){
if(start >= end)
return start;
//设定基准数
int tmp = nums[start];
int i = start;
int j = end;
while(i<j){
//注意这边要使用>=,
//使用>会导致两个数反复交换然后进入死循环
while(i<j && nums[j]<=tmp) j--;
nums[i] = nums[j];
while(i<j && nums[i]>=tmp) i++;
nums[j] = nums[i];
}
//此时i和j相等
nums[i] = tmp;
return i;
}
}
优化
按照上面的代码确实可以AC,但是我们可以看到时间效率和空间效率其实并不高。
我们先来分析一下为什么这种快速排序效率不高。
快速排序的思想是把一个数组分为两等分,如果我们每次找到的基准数排序之后刚好在正中间,那么经过
次排序就能将整个数组排好序了。
但是我们是采用的数组第一个元素作为基准数,那么当数组是升序或者降序排列的时候,我们每次划分数组都是划分为了1和n-1两个极端情况,导致快速排序的效率大大降低,达到了
。
所以问题就成了如何更好的找到基准数。
我们可以采用随机数,我们在partition
函数选取基准数的位置插入一段代码:
Random random = new Random(System.currentTimeMillis());
int randomIndex = random.nextInt(r-l+1)+l;
int tmp = nums[randomIndex];
nums[randomIndex] = nums[start];
nums[start] = tmp;
可以看到效率大大提升了。
当然其实还有更加优秀的优化方法,每次选取最左边、最右边、最中间三个数中的中间值,以这个中间值作为基准数进行划分。