代码搬运工之面试常撕题篇一
熟读力扣300题,不会写题也会敲。
排序
面试官:写个快排吧
你:我擦,幸亏准备了,快排我写的很快。
为什么让你写快排?
因为面试官想看你写得到底有多快,不快的男人不是一个好程序员。
public static void quickSort(int[] nums, int low, int high) {
if (low < high) {
int index = partition(nums, low, high);
quickSort(nums, low, index - 1);
quickSort(nums, index + 1, high);
}
}
public static int partition(int[] nums, int left, int right) {
//基准值
int pivot = nums[left];
while (left < right) {
//从右往左扫描
while (left < right && nums[right] >= pivot) {
right--;
}
//找到第一个比pivot小的元素
if (left < right) nums[left] = nums[right];
//从左往右扫描
while (left < right && nums[left] <= pivot) {
left++;
}
//找到第一个比pivot大的元素
if (left < right) nums[right] = nums[left];
}
//基准数放到合适的位置
nums[left] = pivot;
return left;
}
快排写法很多,这里写的就是以一个元素为基准,找到它应该在位置(排好序后的位置),这个位置上的元素是对的,它右边的元素都比他大,左边的元素都比他小,然后对它左边和右边的也按照这个规则。最终每个元素都找到了自己的位置。
partition这个函数,就是为了给left这个位置的元素找到排序后的位置。
举个用快排思想的题目
BM47 寻找第K大
有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。
给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。
要求:时间复杂度 O(nlogn)O(nlogn),空间复杂度 O(1)O(1)
public static int findKth(int[] a, int n, int K) {
// write code here
int res = quicksort(a,0,a.length-1,K);
return res;
}
public static int quicksort(int []a ,int left , int right,int k){
if(left<right){
int id = partion(a,left,right);
if(id==a.length-k)//如果这个位置正好是第k大的数的位置,直接返回。
return a[id];
if(id<a.length-k)//如果这个位置正好小于第k大的数的位置,只需要对它右边进行快排,因为右边的都比它大。
return quicksort(a,id+1,right,k);
if(id>a.length-k)//同上
return quicksort(a,left,id-1,k);
}
return a[left];
}
private static int partion(int[] a, int left, int right) {
Random random = new Random();
int rand = random.nextInt(right-left+1)+left;//随机一个基准,可以避免在有序的情况下,快排会失效
int pivot = a[rand];
int temp = a[left];
a[left]=pivot;
a[rand]=temp;
while (left<right){
while (left<right && a[right]>=pivot)
right--;
if(left<right)
a[left]=a[right];
while (left<right && a[left]<=pivot)
left++;
if(left<right)
a[right]=a[left];
}
a[left]=pivot;
return left;
}
主要会存在快排失效的问题,会导致个别测试用例不通过,所以要改进一下,基准不是以第一个为准,而是随机生成一个基准,然后和第一个位置交换,其他的和之前的一样。