1.三路快排对比快速排序的优势
相对于快速排序,三路快排的优势是在于能够减少重复元素操作次数
2.三路快排主要的思路
定义lt,gt两个初始变量,[lt,gt]表示该区间的元素等于v
通过遍历每个元素得到lt,gt的最终变量值
3.代码设计
private static void quick(Comparable[] nums, int l, int r){
if (l >= r)
return;
Comparable v = nums[l];
int lt = l;
int gt = r;
// [lt,gt]代表v == e
for (int i = lt ; i <= gt; i ++){
if (v.compareTo(nums[i]) > 0){
if (i != lt)
swap(nums, i, lt);
lt ++;
}
else if(v.compareTo(nums[i]) < 0){
swap(nums, i, gt);
gt --;
i --;
}
}
quick(nums, l, lt - 1);
quick(nums, gt + 1, r);
}
4.
在Leetcode的167号问题
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
- 返回的下标值(index1 和 index2)不是从零开始的。
- 你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
示例:
输入: numbers = [2, 7, 11, 15], target = 9 输出: [1,2] 解释: 2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
解答1:这个问题我们首先想到的是暴利解法,通过两层的遍历来解决问题,这样时间复杂度级别为O(N^2)
解答2::我们想到这个数组是个有序的数组,我们可以遍历每个元素,然后通过二分搜索来找到与之对应的解,这样时间复杂度级别是O(NlogN)
代码如下
class Solution {
public int[] twoSum(int[] numbers, int target) {
int[] res = new int[2];
for (int i = 0; i < numbers.length; i ++){
int j = search(numbers, i + 1, numbers.length - 1 , target - numbers[i]);
if (numbers[i] + numbers[j] == target){
res[0] = i + 1;
res[1] = j + 1;
break;
}
}
return res;
}
private int search(int[] numbers, int l , int r, int res){
if (l >= r){
return l;
}
int mid = (l + r) / 2;
if (numbers[mid] == res)
return mid;
else if (numbers[mid] <= res)
return search(numbers,mid + 1, r, res);
else
return search(numbers, l, mid - 1, res);
}
}
解答三:考虑到这个数组是有序数组,我们可以采用对撞指针来不停的缩小区间来找到最后答案
定义两个初始变量分别指向数组头部和尾部,然后进行遍历操作,每一层遍历缩小一个单位(如果两个值大于target,尾 部缩小一个单位,反之头部增加一个单位),直到找到最后的答案
为什么会这样进行操作呢?
原因如下:当(当前区间)最小值加上最大值都大于target,其他值加上最大值必然大于target,所以尾部可以缩小区间 ,反之亦然
代码如下:
class Solution {
public int[] twoSum(int[] numbers, int target) {
int res[] = new int[2];
int n = 0;
int m = numbers.length - 1;
for (int i = 0; i < numbers.length; i ++){
if (numbers[n] + numbers[m] == target){
res[0] = n + 1;
res[1] = m + 1;
break;
}
else if (numbers[n] + numbers[m] < target){
n ++;
}
else {
m --;
}
}
return res;
}
}