题型一:多路快排
相关题目:75
解题思路:我们平时最常用的快速排序是二路快排,即将数组分为两部分然后分别递归排序。三路快排即将数组分为三部分,中间的部分是等于基准元素的部分,左边是小于基准元素的部分,右边是大于基准元素的部分。三路快排多用于数组中重复元素较多的情况。
例题:
//75
class SortColors {
public void sortColors(int[] nums) {
quickSort3Ways(nums, 0, nums.length-1);
}
private void quickSort3Ways(int[] nums, int start, int end) {
if(start < end) {
int[] divide = partition(nums, start, end);
//递归start到中间区间的左边界-1部分
quickSort3Ways(nums, start, divide[0]-1);
//递归中间区间的右边界到end部分(注意这里右边界不用+1)
quickSort3Ways(nums, divide[1], end);
}
}
//partition函数的返回值是一个数组,因为要返回中间区间的左边界和右边界下标
private int[] partition(int[] nums, int start, int end) {
//基准元素
int refer = nums[start];
//左边界
int left = start;
//右边界
int right = end+1;
//遍历数组的指针
int i = start+1;
//i<right而不是i<end是因为right右边的元素必定大于基准元素
while(i < right) {
//若i遍历到比基准元素小的元素,则交换i所在的元素和左边界+1的元素(+1是因为要始终让基准元素放在数组头)
//然后i后移,左边界后移
if(nums[i] < refer) {
swap(nums, i, left+1);
i++;
left++;
}
//若i遍历到比基准元素大的元素,则交换i所在的元素和右边界的元素
//这里注意i不用后移,因为交换过来的右边界所在元素仍需处理,前面交换过来的左边界所在元素必定比基准元素小所以不用处理
//右边界前移
else if(nums[i] > refer) {
swap(nums, i, right-1);
right--;
}
//若i遍历到与基准元素相等的元素,则i直接后移
else i++;
}
//将数组头的基准元素与中间区间的左边界元素交换
swap(nums, start, left);
//返回中间区间的左右边界下标
int[] divide = {left,right};
return divide;
}
private void swap(int[] nums, int a, int b) {
int temp = nums[a];
nums[a] = nums[b];
nums[b] = temp;
}
}
每天一道LeetCode题,冲!!!