当前位置:   article > 正文

LeetCode - Two Sum I - II - III - IV、3Sum、3Sum Closest、4Sum、4Sum II 系列学习总结_2sum closet

2sum closet

目录

1 - Two Sum

2 - Two Sum II - Input array is sorted

3 - Two Sum III - Data structure design

4 - Two Sum IV - Input is a BST

5 - 3Sum

6 - 3Sum Closest

7 - 3Sum Smaller

8 - 4Sum

9 - 4Sum II


本文将包括上述9个LeetCode中与数列中的元素求和相关的题目,都不是很难,没有 Hard 的题,但是有的题的细节还是值得总结和学习的。

1 - Two Sum

    就是在一个 vector<int> 中找到两个数相加等于题目给出的 target,不能重复用一个数,并且题目只有一个解。

    Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].

  1. vector<int> twoSum(vector<int>& nums, int target) {
  2. unordered_map<int, int> mymap;
  3. vector<int> res;
  4. for (int i = 0; i < nums.size(); i++)
  5. {
  6. // 由于是一边找一边向map中插入,所以 mymap[target - nums[i] 一定小于 i(虽然让这题没要求顺序)
  7. // 由于题目保证只有一组解,所以不需要担心 5,5,5 找 target = 10的情况下,map值被覆盖
  8. // 由于是先找,再赋值,也不需要担心 5,5,6 找 target = 10的情况下,第二个 5 修改 mymap[5] 的值
  9. if (mymap.find(target - nums[i]) != mymap.end())
  10. {
  11. res.push_back(mymap[target - nums[i]]);
  12. res.push_back(i);
  13. return res;
  14. }
  15. mymap[nums[i]] = i;
  16. }
  17. return res;
  18. }

2 - Two Sum II - Input array is sorted

    和第一题一样,区别就是这里的 vector<int> 已经排好序了(sorted in ascending order),找出两个数相加等于target,两个数的索引保证 index1 < index2,并且两个数的索引不是 zero-based 的,也就是索引从1开始。

  1. vector<int> twoSum(vector<int>& numbers, int target)
  2. {
  3. for(int i = 0; i < numbers.size(); i++)
  4. {
  5. if(i > 0 && numbers[i] == numbers[i - 1]) continue;
  6. // 从 numbers.begin() + i + 1 开始找,加速查找,并且避免找到这个数自己
  7. auto ite = find(numbers.begin() + i + 1, numbers.end(), target - numbers[i]);
  8. if(ite != numbers.end())
  9. return vector<int>({i + 1, ite - numbers.begin() + 1});
  10. }
  11. return vector<int>();
  12. }

3 - Two Sum III - Data structure design

    Design and implement a TwoSum class. It should support the following operations:add and find.

    add - Add the number to an internal data structure.
    find - Find if there exists any pair of numbers which sum is equal to the value.

    For example,
    add(1); add(3); add(5);
    find(4) -> true
    find(7) -> false

    这题就是把第一题变成了数据结构的设计。

  1. class TwoSum {
  2. public:
  3. void add(int number) {
  4. ++m[number];
  5. }
  6. bool find(int value) {
  7. for (auto a : m) {
  8. int t = value - a.first;
  9. if ((t != a.first && m.count(t)) || (t == a.first && a.second > 1))
  10. return true;
  11. }
  12. return false;
  13. }
  14. private:
  15. unordered_map<int, int> m;
  16. };

4 - Two Sum IV - Input is a BST

    给出一个二叉树,判断是否有两个节点的 val 相加等于 target,返回 true 或 false。二叉树定义如下:

  1. // Definition for a binary tree node.
  2. struct TreeNode {
  3. int val;
  4. TreeNode *left;
  5. TreeNode *right;
  6. TreeNode(int x) : val(x), left(NULL), right(NULL) {}
  7. };

    dfs代码如下:

  1. bool dfs(TreeNode* root, int k, unordered_set<int>& valset)
  2. {
  3. if(root == NULL)
  4. return false;
  5. if(valset.find(k - root->val) != valset.end())
  6. return true;
  7. valset.insert(root->val);
  8. return(dfs(root->left, k, valset) || dfs(root->right, k, valset));
  9. }
  10. bool findTarget(TreeNode* root, int k)
  11. {
  12. unordered_set<int> valset;
  13. return dfs(root, k, valset);
  14. }

5 - 3Sum

    在一个 vector<int> 中找到所有的满足 a + b + c = 0 的 unique 的三元组,比如

    Given array nums = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]

    直接用一个数 i 从 0 走到 n - 2 的位置,另外两个数从 i + 1 和 n - 1 想内夹逼即可。

  1. vector<vector<int>> threeSum(vector<int>& nums)
  2. {
  3. vector<vector<int> > res;
  4. int n = nums.size();
  5. if (n < 3) return res;
  6. sort(nums.begin(), nums.end());
  7. for (int i = 0; i < n - 2; i++)
  8. {
  9. if (nums[i] > 0) break; // 因为是sorted,所以第一个数大于0肯定就过了
  10. if (i > 0 && nums[i - 1] == nums[i]) continue; // 跳过相同的数
  11. int l = i + 1, r = n - 1;
  12. while (l < r)
  13. {
  14. int a = nums[i], b = nums[l], c = nums[r];
  15. int sum = a + b + c;
  16. if (sum == 0)
  17. {
  18. res.push_back(vector<int>({ a, b, c }));
  19. while (b == nums[++l]); // 跳过相同的数
  20. while (c == nums[--r]); // 跳过相同的数
  21. // 相当于
  22. // while(nums[l + 1] == b) ++l;
  23. // while(nums[r - 1] == c) --r;
  24. // ++l; --r;
  25. }
  26. else if (sum > 0) --r;
  27. else ++l;
  28. }
  29. }
  30. return res;
  31. }

6 - 3Sum Closest

    找出一组 a, b, c 三个数加起来与 target 最接近,也就是 abs(a + b + c - target) 最小,题目保证只有一组解。

    这道题和上边的求和等于0一个意思,不过判断条件变了,但是值得注意的是这题不能像 3 sum 一题中用 while (b == nums[++l]) 方式跳过一些相同的数,一个是因为求和 == target 的话就返回了,因为这肯定是最好的情况,另个一个原因是因为比如 -1, 0, 1, 1, 55,当 l 指向第一个1时,不能因为后边也是1就直接向后走,因为可能也会由于 l < n 的限制导致r走不到 1 这个位置。

  1. int threeSumClosest(vector<int>& nums, int target)
  2. {
  3. int res = -1;
  4. int diff = 9999;
  5. int n = nums.size();
  6. sort(nums.begin(), nums.end());
  7. for (int i = 0; i < n - 2; i++)
  8. {
  9. if(i > 0 && nums[i] == nums[i - 1]) continue; // 跳过相同的数
  10. int l = i + 1, r = n - 1;
  11. while (l < r)
  12. {
  13. int ln = nums[l], rn = nums[r];
  14. int tmp_sum = nums[i] + ln + rn;
  15. int tmp_diff = abs(tmp_sum - target);
  16. if (tmp_diff == 0) return target; // 0肯定是最好的情况了
  17. if (tmp_diff < diff)
  18. {
  19. res = tmp_sum;
  20. diff = tmp_diff;
  21. }
  22. if (tmp_sum < target) ++l;
  23. else if (tmp_sum > target) --r;
  24. }
  25. }
  26. return res;
  27. }

7 - 3Sum Smaller

Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.

For example, given nums = [-2, 0, 1, 3], and target = 2.

Return 2. Because there are two triplets which sums are less than 2:

  1. [-2, 0, 1]
  2. [-2, 0, 3]

    题目要求找出所有满足 nums[i] + nums[j] + nums[k] < target 的 i, j, k 的三元组,返回三元组的个数。并且题目要求 O(n2)的时间。

    和上一题一样,只不过判断又变了,三道 3Sum 的题的中心思想都是一个数 i 从 0 走到 n - 2 的位置,另外两个数每次从 i + 1 和 n - 1 想内夹逼,三道题不同的点就是这两个数夹逼的方式变了。

  1. int threeSumSmaller(vector<int>& nums, int target) {
  2. if (nums.size() < 3) return 0;
  3. int res = 0, n = nums.size();
  4. sort(nums.begin(), nums.end());
  5. for (int i = 0; i < n - 2; ++i) {
  6. int left = i + 1, right = n - 1;
  7. while (left < right) {
  8. if (nums[i] + nums[left] + nums[right] < target) {
  9. res += right - left; // 如果求和小于target了,那么right从当前位置一直减到left,求和一定都小于target
  10. ++left;
  11. }
  12. else
  13. --right;
  14. }
  15. }
  16. return res;
  17. }

8 - 4Sum

    和3Sum一样,找出所有相加等于target的不重复的四元组。方法和3Sum也很类似,不过是两个数从左往右,然后两个数在后边夹逼。

  1. vector<vector<int> > fourSum(vector<int> &nums, int target)
  2. {
  3. set<vector<int> > nset; // 用set来保证没有重复,其实用vector也没有问题
  4. int n = nums.size();
  5. sort(nums.begin(),nums.end());
  6. for(int i = 0; i < n - 3; i++)
  7. {
  8. if(nums[i] > target / 4) break; // 加上这句会快很多!!
  9. if(i > 0 && nums[i] == nums[i - 1]) continue;
  10. for(int j = i + 1; j < n - 2; j++)
  11. {
  12. if(j > i + 1 && nums[j] == nums[j - 1]) continue;
  13. int l = j + 1, r = n - 1;
  14. while(l < r)
  15. {
  16. int ln = nums[l], rn = nums[r];
  17. int tmp_sum = nums[i] + nums[j] + ln + rn;
  18. if(tmp_sum == target)
  19. {
  20. nset.insert(vector<int>({nums[i], nums[j], ln, rn}));
  21. //while(nums[l + 1] == ln) ++l; // 可以用while跳过重复数字,但是这道题中会变慢
  22. //while(nums[r - 1] == rn) --r;
  23. ++l; --r;
  24. }
  25. else if(tmp_sum > target)
  26. {
  27. --r;
  28. //while(nums[r - 1] == rn) --r; // 可以用while跳过重复数字,但是这道题中会变慢
  29. }
  30. else
  31. {
  32. ++l;
  33. //while(nums[l + 1] == ln) ++l; // 可以用while跳过重复数字,但是这道题中会变慢
  34. }
  35. }
  36. }
  37. }
  38. return vector<vector<int> >(nset.begin(), nset.end());
  39. }

 9 - 4Sum II

    题目给出4个相同大小的 vector<int>,然后找出四元组 i, j, k, l 满足 A[i] + B[j] + C[k] + D[l] = 0,返回这样玩的四元组的个数。值得注意的是,四元组是不能重复的,不过四个数加起来等于0的组合可以使重复的,这样我们只需要记录这4个数组各有哪些数,然后计算这些数组合加起来等于0的情况,比如1 + 2 - 1 - 2 =0,A中有两个1,那么就是两种四元组。

    代码中,在前两个数组中,对数进行组合,记录组合求和之后的数,比如 1 + 2 和 2 + 1,那么就代表,数组A+B中有两个3,再在A+B这个数组中,遍历查找有没有后边两个数组所有数的组合的相反数(这样四个数组组合加起来就是0了),就可以得到满足条件的组合,并且这样计算 1 + 2 - 2 - 1 和 2 + 1 - 2 - 1,不需要计算两次,只需要知道 3 - 2 - 1 = 0,然后A+B中有两个3就知道有两种组合了。

  1. int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D)
  2. {
  3. unordered_map<int, int> abSum;
  4. for(auto a : A)
  5. for(auto b : B)
  6. ++abSum[a+b];
  7. int count = 0;
  8. for(auto c : C)
  9. {
  10. for(auto d : D)
  11. {
  12. auto it = abSum.find(0 - c - d);
  13. if(it != abSum.end())
  14. count += it->second;
  15. }
  16. }
  17. return count;
  18. }

    

    

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/366053
推荐阅读
相关标签
  

闽ICP备14008679号