相关文章如下所示:
LeetCode算法 —— 最接近的三数之和(排序 / 双指针原理)
题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
为何排序:将数组排序好之后,可以大大的提高算法的效率,利用双指针原理进行工作,可以减少大量的重复判断
为何使用双指针:使用双指针可以将复杂度降到O(n),大大的提高效率 . . .
代码如下所示:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> retArr;
if (nums.size() < 3) return retArr;
if (nums.size() == 3) {
if (nums[0] + nums[1] + nums[2] == 0)
retArr.push_back(nums);
return retArr;
}
// 排序,性能优化(双指针操作基于此原理)
sort(nums.begin(), nums.end());
int nSize = nums.size();
for (size_t i = 0; i < nSize; i++) {
// 跳过重复 前面的数已经把可能性测试过了
if (i > 0 && nums[i] == nums[i - 1]) continue;
// i + 1 跳过重复,前面的数应该都和当前的数比较过了
auto result = twoSum(nums, i + 1, nSize - 1, -nums[i], nums[i]);
retArr.insert(retArr.end(), result.begin(), result.end());
}
return retArr;
}
private:
vector<vector<int>> twoSum(vector<int>& nums, int start, int end, int target, int value) {
vector<vector<int>> answer;
// 双指针原理
while (start < end) {
int sum = nums[start] + nums[end];
if (sum == target) {
answer.push_back({ value,nums[start],nums[end] });
// 该数已经判断过了,跳过该数
while (start < end && nums[start] == nums[start + 1]) {
++start;
}
++start;
while (start < end && nums[end] == nums[end - 1]) {
--end;
}
--end;
}
else if (sum < target) {
++start;
}
else {
--end;
}
}
return answer;
}
};
三处代码解释:
1)第一处:
如果 nums[i] == nums[i - 1],那么则进行下次循环,因为此数组是排序好的,所以先将 nums[i - 1] 的所有可能性已经判断好了,而 nums[i] == nums[i - 1],所以 nums[i] 就不需要判断了,直接跳过就好 . . .
.
2)第二处:
为什么从 i + 1开始,而不是 0?如果每次从0开始,会有大量重复的数据,从 i + 1开始,每次的范围都不一样,后面的都比前面的大,前面都已经判断过了,所以不需要在在区域内重新的判断 . . .
.
3)第三处:
nums[start] 和 nums[end] 已经判断过了,所以下次判断就不需要了,循环表示的意义是过滤掉所有一样的值,比如一堆数据 5 5 5 5 6,第一个5已经判断过了,所以下次不允许重复,则直接判断到 6的地方 . . .
.
.
.