题目:力扣https://leetcode-cn.com/problems/sort-colors/
class Solution {
public void sortColors(int[] nums) {
quickSort(nums,0,nums.length-1);
}
private void swap(int[] nums,int index1,int index2){
nums[index1] ^= nums[index2];
nums[index2] ^= nums[index1];
nums[index1] ^= nums[index2];
}
private void quickSort(int[] nums,int l,int r){
if(l >= r){
return;
}
int left = l;
int right = r;
int pivot = nums[left];
while(left < right){
if(left < right && nums[right] >= pivot){
right--;
}
if(left < right){
swap(nums,left,right);
}
if(left < right && nums[left] <= pivot){
left++;
}
if(left < right){
swap(nums,left,right);
}
}
quickSort(nums,l,right-1);
quickSort(nums,left+1,r);
}
}
思路:这是一道很平常的排序题,有种开挂的方法就是直接Arrays.sort(nums)直接解决战斗。当然如果这么提交的话明显对不住“中等”的难度设定,因此我选择了手写。大概思路就是,位运算交换+快速排序。位运算交换属于一种稍稍有点抖机灵的实现方式,今天刚学会顺带用这道题练练手,快速排序之间在leetcode56.合并区间也用过,这里也是大同小异。
1.位运算交换。我们知道加减乘除的底层也是通过位运算来实现的,因此与其相比位运算的效率会占优一些。^这个是抑或运算符,抑或运算的法则:两数相同则结果为1;两数不同则结果为0。因此,我们可以得出两条定律:(1)0^N=N2(2)N^N=0。清楚了这些之后,现在开始举例说明。例如:
int a = 甲;
int b = 乙;
a = a ^ b; //a = 甲 ^ 乙 b = 乙
b = a ^ b; //a = 甲 ^ 乙 b = 甲 ^ 乙 ^乙 = 甲
a = a ^ b; //a = 甲 ^ 乙 ^ 甲 = 乙 b = 甲
这样就完成了通过位运算交换数组中的两个元素。值得一提的是,由于位运算的特点,这种方法适用于两个元素的地址一定是独立的(是地址,不是值,尽管两个元素的值相同也可以正常交换),如果地址相同则会把数据抹去变成0。
private void swap(int[] nums,int index1,int index2){
nums[index1] ^= nums[index2];
nums[index2] ^= nums[index1];
nums[index1] ^= nums[index2];
}
2.快速排序。选定任意数为pivot,然后比对左右指针指向的元素,小于pivot的放左侧,大于pivot的放右侧。通过递归调用的方法,先比对左半部分,再比对右半部分。详细的叙述可以参考之前写过的题目——leetcode56.合并区间。
private void quickSort(int[] nums,int l,int r){
if(l >= r){
return;
}
int left = l;
int right = r;
int pivot = nums[left];
while(left < right){
if(left < right && nums[right] >= pivot){
right--;
}
if(left < right){
swap(nums,left,right);
}
if(left < right && nums[left] <= pivot){
left++;
}
if(left < right){
swap(nums,left,right);
}
}
quickSort(nums,l,right-1);
quickSort(nums,left+1,r);
}