返回
Featured image of post Leetcode12

Leetcode12

两数之和&三数之和


167.两数之和 II - 输入有序数组:fire:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class Solution {
public:
    vector<int> twoSum(vector<int> &numbers, int target) {
        int left = 0, right = numbers.size() - 1;
        for (;;) { // left < right
            int s = numbers[left] + numbers[right];
            if (s == target) return {left + 1, right + 1};
            s > target ? --right : ++left;
        }
    }
};
总结

若是暴力做法,直接是n方的复杂度,但是需要用上有序列表的条件;

例如 2 3 4 8 9 一开始选择2 9 若是得到6,那么11大于6,9已经是最大的了,若还是2右移为3,那么更加大了,只有9左移;同理,若是比target小的时候,左边的数小,右移动;

这是关键思想,之后三数之和也是这个思路;

灵神的题解更简洁,其中这道题保证唯一有解,所以一开始进入一个无限循环;

用三目运算更方便;

错解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int n=numbers.size();
        int left=0,right=n-1;
        vector<int> res;
        while(left<right){
            if(numbers[left]+numbers[right]>target)
                right--;
            else if(numbers[left]+numbers[right]<target)
                left++;
            else{
                res.emplace_back(left+1);
                res.emplace_back(right+1);
            // break;
                        return res;

            }
                
        }   
                        // return res;
//  return {left + 1, right + 1};
    }
};

错因在于对于循环控制条件没有写好,编译器认为你没有考虑完所有情况;这时要么别用这种if elseif结构;要么对其中进行break,可以解决报错;

修改后

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
class Solution {
public:
    vector<int> twoSum(vector<int>& numbers, int target) {
        int n=numbers.size();
        int left=0,right=n-1;
        while(left<right){
            if(numbers[left]+numbers[right]>target)
                right--;
            else if(numbers[left]+numbers[right]<target)
                left++;
            else
                break;                
        }   
        return {left + 1, right + 1};
    }
};

其中vector可以写成这样也需要注意;

15.三数之和:fire::fire:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Solution {
public:
    vector<vector<int>> threeSum(vector<int> &nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int n = nums.size();
        for (int i = 0; i < n - 2; ++i) {
            int x = nums[i];
            if (i && x == nums[i - 1]) continue; // 跳过重复数字
            if (x + nums[i + 1] + nums[i + 2] > 0) break; // 优化一
            if (x + nums[n - 2] + nums[n - 1] < 0) continue; // 优化二
            int j = i + 1, k = n - 1;
            while (j < k) {
                int s = x + nums[j] + nums[k];
                if (s > 0) --k;
                else if (s < 0) ++j;
                else {
                    ans.push_back({x, nums[j], nums[k]});
                    j++;//形如 2 3 4 5 已经有了2 5 再找 3 4
                    while(j<k&&nums[j] == nums[j - 1])
                        ++j;
                    k--;
                    while(j<k&&nums[k] == nums[k + 1])
                        --k;                        
                    
                }
            }
        }
        return ans;
    }
};
总结

其实就是先定下来i,然后在i的基础上做j与k的两数之和;

最后要考虑清晰关于重复数字的情况,一步步来考虑,别一开始就考虑重复数字的情形;

此处好几个难点

        if (x + nums[i + 1] + nums[i + 2] > 0) break; // 优化一
        if (x + nums[n - 2] + nums[n - 1] < 0) continue; // 优化二

优化2处不可以用break,因为优化1处,当前i 与它之后的两个必定是此时所有数最小的了,之后没有比他更小的了,break;

但是当前i加上数组末尾的两个数确实不是当前最大的,因为i不一定是倒数第三;这个前往小心

附录

参考文献

版权信息

本文原载于[Alvarez’s Blog](Alvarez’s Blog (akihi878.github.io)),遵循CC BY-NC-SA 4.0协议,复制请保留原文出处。

Licensed under CC BY-NC-SA 4.0
本博客已稳定运行
⛄发表了4篇文章 · ✍总计0.99k字
使用 Hugo 构建
主题 StackJimmy 设计