23/1/29-LeetCode 15: 3Sum
LeetCode 15: 3Sum
写过了2sum,现在再来写3sum,虽然大一下数据结构是写过的orz,应该是写过的,但是某人忘得很彻底。。。没事不迟!
0.回顾一下2sum
在一维array数组里找到两个数(非自身结合),使得两数之和等于target。array和target给定。
- 解决方法:利用哈希,对array从前向后遍历
- 如果(target-arrayi) 在哈希表中搜索false,则将arrayi存入哈希表;
- 如果(target-arrayi) 在哈希表中搜索true,OK! return true;
ok来思考3sum
要求
- 找到所有三元组,三个元素的顺序无所谓,不同组不同内容(数字不一样);
- 要求组内元素在array中不同下标;
思路
不重复
- 对三元组(a,b,c)保证a b c的顺序,避免排列组合类型的重复。于是a≤b≤c,即排序好后,a左 b中 c右;
- 从小到大遍历a,保证a严格单调递增;
所以a的严格单调递增保证了(b+c)的严格单调递减,这里就运用双指针的处理方法。
双指针
以此来确定b c具体的值。
在a严格单调递增 and a≤b≤c的条件下,保证b严格单调递增,c严格单调递减。
- 第一层for是 a 的严格单调递增
- 第二层for是双指针b 的严格单调递增,在这里面while寻找c
细节问题:a/b/c都不可以与上一个自己重复,但是a=b=c的情况是允许的。
实现
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int nsize = nums.size();
//保证单调性 先对数组从大到小排序
sort(nums.begin(), nums.end());
vector<vector<int>> ans;//存储答案的二维数组
if(nums[0] > 0) return ans;
// enumerate a and make sure that a is strictly monotonically increasing
for (int first = 0; first < nsize - 2; ++first) {
// 需要和上一次枚举的数不相同--严格 其实这里换成nsize-2也可以过
//还有这里 如果没有first>0这条 first-1=-1时是非法内存访问
if (first > 0 && nums[first] == nums[first - 1])
continue;
//第一层for下面 doubly pointer -- second=b third=c
// c 对应的指针初始指向数组的最右端
int third = nsize - 1;
//要求最后三元组的和 = 0
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < nsize - 1; ++second) {
// second不能和上一个second相等 但是可以和first相等
if (second > first + 1 && nums[second] == nums[second - 1])
continue;
// 保证数组中 b 在 c 的左侧 反正不能相遇
while (second < third && nums[second] + nums[third] > target)
--third;
// 如果b c指针相遇 则这组无解 将 b 右移:使 b 严格递增 然后重新从最右遍历c
if (second == third) break;
if (nums[second] + nums[third] == target)
ans.push_back({nums[first], nums[second], nums[third]});
//找到了一个三元组 继续严格单调递增 b 的值 a的值 寻找所有解之后总的return
}
}
return ans;
}
};

浙公网安备 33010602011771号