algs4-1.4.15: 用双指针代替两层循环, 实现线性级别的算法
1.4.15 快速3-sum。作为热身,使用一个线性级别的算法(而非基于二分查找的线性对数级别的算法)实现TwoSumFaster来计算已排序的数组中和为0的整数对的数量。用相同的思想为3-sum问题给出一个平方级别的算法。
我的初版答案: 基于1.4.14 GPT4的双指针解法, 快速改了下.
public class TwoSumFast1415 {
public static int count(int[] nums) {
Arrays.sort(nums);
int N = nums.length;
int count = 0;
int target = 0;
int left = 0, right = N - 1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum == target) {
count++;
while (left < right && nums[left] == nums[left + 1])
left++; // Prevents duplications
while (right > left && nums[right] == nums[right - 1])
right--; // Prevents duplications
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
return count;
}
}
public class ThreeSumFast1415 {
public static int count(int[] nums) {
Arrays.sort(nums);
int N = nums.length;
int target = 0;
int count = 0;
for (int i = 0; i < N - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) // Prevents duplicate results
continue;
if (nums[i] + nums[i + 1] + nums[i + 2] > target) // min > target
break;
int left = i + 1, right = N - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == target) {
count++;
while (left < right && nums[left] == nums[left + 1])
left++; // Prevents duplications
while (right > left && nums[right] == nums[right - 1])
right--; // Prevents duplications
left++;
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
return count;
}
}
问问GPT4
问: 是否符合题目要求?
这两段代码均满足了题目要求:
TwoSumFast1415
类中的count
函数:- 此函数采用了线性时间复杂度的算法(而非二分查找),这是通过使用两个指针(一个从起始位置开始,另一个从末尾开始,共同向中心移动)实现的。
- 先排序数组,然后遍历数组,将和等于0的不重复整数对计数并返回。
ThreeSumFast1415
类中的count
函数:- 使用的是平方级别的算法。在外层有一个用于遍历每一个数的循环;在内层,使用了类似于
TwoSumFast
中的双指针方法,对每一次外层循环找出目标的和等于0的对。 - 它也避免计算重复的整数对,并在确定最小可能和大于目标时提前结束。
- 使用的是平方级别的算法。在外层有一个用于遍历每一个数的循环;在内层,使用了类似于
所以,以上代码完全符合题目的要求,良好的完成了任务。
问: 从算法实现角度, 有无可能进一步优化, 让运行效率更快?
两个算法已经非常有效率,对于 TwoSumFast
的实现,其时间复杂度已经达到最优 —— O(n)。对于 ThreeSumFast
,其时间复杂度为 O(n^2),这在没有更多信息可以用来减小搜索空间的情况下,也是最优的。
补充: 贴下 ThreeSum 各个版本的代码的执行时间.
/*
* ThreeSum:
* 1Kints time:0.082 s;count: 70
* 2Kints time:0.5 s;count: 528
* 4Kints time:2.07 s;count: 4039
* 8Kints time:16.147 s;count: 32074
*
* ThreeSumFast:
* 1Kints time:0.033 s;count: 70
* 2Kints time:0.062 s;count: 528
* 4Kints time:0.26 s;count: 4039
* 8Kints time:1.146 s;count: 32074
*
* ThreeSumFast1415:
* 1Kints time:0.015 s;count: 70
* 2Kints time:0.009 s;count: 528
* 4Kints time:0.022 s;count: 4039
* 8Kints time:0.08 s;count: 32074
*/