数组算法:二分、快排
典型的排序算法思想、二分查找思想在解 LeetCode 题目时很有用。
5.颜色分类
给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库的sort函数的情况下解决这个问题。
题解:定义前后指针 red(0) blue(2),遍历数组,若元素为0 则放置数组前方,若元素为2 ,则放置数组后方,非0 非2 即为1,使用变量temp,每次将其交换放置中间(非前非后即为中间)。
注意事项:for遍历的边界应为 blue + 1 (blue动态改变),不能为nums.length。不然会将数组后面已整理好的元素重新交换一遍。(此处有疑问可自行上机debug即可解决)
class Solution {
public void sortColors(int[] nums) {
//定义temp用于将所有非0 非2元素往中间塞入
int red = 0,blue = nums.length-1,temp = 0;
for(int i = 0;i <blue+1;i++){
if(nums[i] == 0){
temp = nums[red];
nums[red++] = nums[i];
nums[i] = temp;
}if(nums[i] == 2){
temp = nums[blue];
nums[blue--] = nums[i];
nums[i] = temp;
//避免遗漏 末尾相邻元素交换,可能发生遗漏
i--;
}
}
}
}
6.数组中的第K个最大元素
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
思路:快排。
快排复习:
首先我们来回顾一下快速排序,这是一个典型的分治算法。我们对数组 a[l⋯r]做快速排序的过程是(参考《算法导论》):
分解: 将数组 a[l⋯r]「划分」成两个子数组 a[l⋯q−1]、a[q+1⋯r],使得 a[l⋯q−1]中的每个元素小于等于 a[q],且 a[q] 小于等于 a[q+1⋯r]中的每个元素。其中,计算下标 q也是「划分」过程的一部分。
解决: 通过递归调用快速排序,对子数组 a[l⋯q−1]和 a[q+1⋯r]进行排序。
合并: 因为子数组都是原址排序的,所以不需要进行合并操作,a[l⋯r]已经有序。
上文中提到的 「划分」 过程是:从子数组 a[l⋯r]中选择任意一个元素 xxx 作为主元,调整子数组的元素使得左边的元素都小于等于它,右边的元素都大于等于它, x 的最终位置就是 q。
评论区参考题解:
class Solution {
Random rand=new Random();
public int findKthLargest(int[] nums, int k) {
return quickSort(nums,k,0,nums.length-1);
}
private int quickSort(int[] nums,int k,int left,int right){
int index=rand.nextInt(right-left+1)+left;
int flag=nums[index]; //定义随机数组下标对应元素为 flag
nums[index]=nums[left];//将数组最左边元素赋值给 index指向元素:第一轮循环遍历中最左边会被覆盖,因此提取将 nums[left] 存入 nums[index],反正nums[index] 事先用flag存过了,最后再赋值即可。
int i=left,j=right;
while (i<j){
while (i<j&&nums[j]<=flag) j--; //从右边往左遍历,元素大于flag元素,挪到左边
nums[i]=nums[j];
while (i<j&&nums[i]>=flag) i++; //从左边向右边遍历,元素小于flag元素,挪到右边
nums[j]=nums[i];
}
for(int i = left;i < j;i++){
if(i < j && nums[i]<= flag){
nums[j--] = nums[i++];
}
if(i < j && num[j] >= flag){
nums[i++] = nums[j--];
}
}
nums[i]=flag; //将之前存好的flag元素插回
if (i==k-1) return nums[i]; //快排每次唯一确定一个flag数位置
else if (i<k-1) return quickSort(nums,k,i+1,right);//递归右子数组
else return quickSort(nums,k,left,i-1); //递归左子数组
}