例题:颜色分类
给定一个包含红色、白色和蓝色,一共 n 个元素的数组,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
此题中,我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
注意: 不能使用代码库中的排序函数来解决这道题。
首先,最简单的思路是使用计数排序,因为只有三个元素。
其次,可以使用三路快排思想。维护三个指针 zero
,i
, two
,让它们满足:
arr[0...zero] == 0,arr[zero+1...i-1] == 1,arr[two...n-1] == 2。
使用i遍历数组,当nums[i]:
- ==1,i++
- ==0,swap(nums[i],nums[++zero]) , i++
- ==2,swap(nums[i],nums[–tow])
当i = two的时候停止。
代码如下:
class Solution {
public void sortColors(int[] nums) {
int zero = -1;
int two = nums.length;
for(int i=0;i<two;){
if(nums[i]==0){
swap(nums,i,++zero);
i++;
}else if(nums[i]==1){
i++;
}else{
swap(nums,i,--two);
}
}
}
public void swap(int[] nums,int i,int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
1.合并两个有序数组(归并思想)
给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 num1 成为一个有序数组。
说明:
·初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
·你可以假设 nums1 有足够的空间(空间大小大于或等于 m + n)来保存 nums2 中的元素
归并排序的思想中,就是两个有序数组进行合并,这里则更加简单。不过既然是放在nums1中,而不是新建一个数组,那么就要从m-1和n-1分别向前遍历,然后从nums1的m+n-1处向前存储。
时间复杂度:O(m+n)
class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
//从后向前遍历可以避免使用额外空间
int p = m + n -1;
int p1 = m -1;
int p2 = n -1;
while(p1>=0 && p2>=0){
if(nums1[p1]>nums2[p2]){
nums1[p--] = nums1[p1--];
}else{
nums1[p--] = nums2[p2--];
}
}
while(p2>=0){
nums1[p--] = nums2[p2--];
}
}
}
2.数组中的第K个最大元素(快排思想)
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
之前做过这个题,不过当时用的是优先队列。现在使用快排思想,快排就是使一个元素快速到达它在排序数组中的正确位置。那么这个题的做法就是:
- 如果
l==nums.length-k
,那么此时nums[x]就是要找的值; - 如果
l<nums.length-k
,那么说明第k个最大元素在x右边,在右边继续快排; - 如果
l>nums.length-k
,那么说明第k个最大元素在x左边,在左边继续快排。
class Solution {
int res;
public int findKthLargest(int[] nums, int k) {
findK(nums,0,nums.length-1,k);
return res;
}
public void findK(int[] nums,int left,int right,int k){
int l = left;
int r = right;
if(l==r) res = nums[l];
if(l<r){
int x = nums[left];
while(l<r){
while(l<r && nums[r]>x){
r--;
}
if(l<r){
nums[l] = nums[r];
l++;
}
while(l<r && nums[l]<x){
l++;
}
if(l<r){
nums[r] = nums[l];
r--;
}
}
System.out.println("");
if(l==nums.length-k) res = x;
if(l<nums.length-k) findK(nums,l+1,right,k);
if(l>nums.length-k) findK(nums,left,l-1,k);
}
}
}