15.三数之和
15. 三数之和 - 力扣(LeetCode)
题目解析:
这道题目说是三数之和,其实这和我们之前做过的两数之和是一个规律的~无非就是我们需要实时改动target的值。先排好序,然后固定一个数取其负值作target,然后我们再从除固定数以外的范围内寻找两数之和为target的数,这样再与固定数相加就得到0了,形成三元数组。
算法解析:
这就是两数和的核心图解,唯一区别就是我们的target值是随着固定数的变化而发生改变的~
废话不多说,本题的难点就在于去重以及去重时的越界问题。因为按照题目规定类似于
【-1,0,-1】与【-1,-1,0】这种会算重复项只能取其一,而这也是我们优先选择排序的原因,在排行序后二者就变为【-1,-1,0】,更容易去重。
去重分两个阶段,一是【left,right】范围之间的去重,另一个是固定数first遍历数组的去重。
所以我们给出的去重方案就是观察移动前后的数值是否相同,如果相同那就再移动一位,直到不同为止。不过这样也引发了新的问题:越界~
我们发现left与right的选取是需要在【left,rigtht】这个界限里面的,所以只需要加上一层条件即可(left<right)~
固定数first同理:
代码:
class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {vector<vector<int>> ret;sort(nums.begin(), nums.end());int n = nums.size();int first = 0;while (first <= n - 3){//小优化if (nums[first] > 0) break;int left = first + 1;int right = n - 1;int target = -nums[first];//一轮比较while (left < right){int sum = nums[left] + nums[right];if (sum > target){--right;}else if (sum < target){++left;}else{ret.push_back({ nums[first],nums[left],nums[right] });right--;left++;//left与right去重while (left < right && nums[right + 1] == nums[right]){right--;}while (left < right && nums[left - 1] == nums[left]){left++;}}}//固定数去重first++;while (first < n && nums[first - 1] == nums[first]){first++;}}return ret;}
};
18.四数之和
18. 四数之和 - 力扣(LeetCode)
题目解析:
四数之和别看多了一个数,其实和三数之和还是同一个模板,没有本质区别
算法解析:
找四数之和我们可以先拆分成固定数a与三数之和,那么三数之和的值就得为target-a。这样a与三数之和才相加才可以变为target,而在三数之和中就得拆分成固定数b与两数之和,那么两数之和的值就得为target-a-b,这样才能与b相加得到target-a。
所以只要在三数之和的代码中把控好target-a-b的值就行了,除此之外再多加一个对固定数a的去重就好了~
代码:
在三数之和外套一层固定数a的循环以及去重复,另外改变目标值t变为target-a-b就差不多了。
class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;sort(nums.begin(), nums.end());int n = nums.size();int a = 0;//固定数awhile (a <= n - 4){//固定数bint b = a + 1;while (b <= n - 3){int left = b + 1;int right = n - 1;//防止数据溢出强转类型long long t = (long long)target - nums[b] - nums[a];while (left < right){int sum = nums[left] + nums[right];if (sum > t){--right;}else if (sum < t){++left;}else{ret.push_back({ nums[a],nums[b],nums[left],nums[right] });right--;left++;//一级去重复while (left < right && nums[right + 1] == nums[right]){right--;}while (left < right && nums[left - 1] == nums[left]){left++;}}}//二级去重b++;while (b < n && nums[b - 1] == nums[b]){b++;}}//三级去重a++;while (a < n && nums[a - 1] == nums[a]){a++;}}return ret;}
};