数组:求和

2021-06-02 每日一题 LeetCode

# 0001. 两数之和 (opens new window)

题目

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

示例 1:

输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
1
2
3

示例 2:

输入:nums = [3,2,4], target = 6
输出:[1,2]
1
2

示例 3:

输入:nums = [3,3], target = 6
输出:[0,1]
1
2

提示:

  • 2 <= nums.length <= 10^4
  • -10^9 <= nums[i] <= 10^9
  • -10^9 <= target <= 10^9
  • 只会存在一个有效答案

进阶:你可以想出一个时间复杂度小于 O(n^2) 的算法吗?

解析

使用 Hash 表记录所有已遍历元素及对应的下标,遍历的同时查找满足条件的数字是否已遍历,若找到返回即可。

代码

    # 0015. 三数之和 (opens new window)

    题目

    给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != kj != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

    你返回所有和为 0 且不重复的三元组。

    注意:答案中不可以包含重复的三元组。

    示例 1:

    输入:nums = [-1,0,1,2,-1,-4]
    输出:[[-1,-1,2],[-1,0,1]]
    解释:
    nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
    nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
    nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
    不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
    注意,输出的顺序和三元组的顺序并不重要。
    
    1
    2
    3
    4
    5
    6
    7
    8

    示例 2:

    输入:nums = [0,1,1]
    输出:[]
    解释:唯一可能的三元组和不为 0 。
    
    1
    2
    3

    示例 3:

    输入:nums = [0,0,0]
    输出:[[0,0,0]]
    解释:唯一可能的三元组和为 0 。
    
    1
    2
    3

    提示:

    • 3 <= nums.length <= 3000
    • -10^5 <= nums[i] <= 10^5

    解析

    由于需要求三个数字的和,遍历复杂度不会小于 O(n2)O(n^2),因此可以先对数组排序,这样方便之后处理。

    整体思路为,通过遍历数组选取第一个数字,在遍历的同时用前后双指针寻找满足条件的数字即可。

    代码

      # 0016. 最接近的三数之和 (opens new window)

      题目

      给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。

      返回这三个数的和。

      假定每组输入只存在恰好一个解。

      示例 1:

      输入:nums = [-1,2,1,-4], target = 1
      输出:2
      解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
      
      1
      2
      3

      示例 2:

      输入:nums = [0,0,0], target = 1
      输出:0
      
      1
      2

      提示:

      • 3 <= nums.length <= 1000
      • -1000 <= nums[i] <= 1000
      • -10^4 <= target <= 10^4

      解析

      本题思路与 0015. 三数之和 类似,只是更新结果的条件变为比较差值的大小,保留差值更小的结果。

      代码

        # 0018. 四数之和 (opens new window)

        题目

        给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

        • 0 <= a, b, c, d < n
        • abcd 互不相同
        • nums[a] + nums[b] + nums[c] + nums[d] == target

        你可以按 任意顺序 返回答案 。

        示例 1:

        输入:nums = [1,0,-1,0,-2,2], target = 0
        输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
        
        1
        2

        示例 2:

        输入:nums = [2,2,2,2,2], target = 8
        输出:[[2,2,2,2]]
        
        1
        2

        提示:

        • 1 <= nums.length <= 200
        • -10^9 <= nums[i] <= 10^9
        • -10^9 <= target <= 10^9

        解析

        本题思路与 0015. 三数之和 相同,只需增加一层循环,枚举前两个数字的值,双指针确定后两个数字的值即可。

        代码

          # 0167. 两数之和 II - 输入有序数组 (opens new window)

          题目

          给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

          函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

          你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

          解析

          由于数组有序,因此使用前后双指针移动寻找目标值即可。

          代码

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

          # 0259. 较小的三数之和 (opens new window)

          题目

          给定一个长度为 n 的整数数组和一个目标值 target,寻找能够使条件 nums[i] + nums[j] + nums[k] < target 成立的三元组  i, j, k 个数(0 <= i < j < k < n)。

          解析

          首先对数组排序,之后遍历枚举第一个数字,前后双指针寻找满足条件的后两个数字。

          这里用到一个技巧,即:ans += high - low,由于 high 的位置满足条件,因此 low 和 high 之间的所有数字均满足条件,直接累加即可。

          代码

          class Solution {
          public:
              int threeSumSmaller(vector<int>& nums, int target) {
                  int ans = 0;
                  if (nums.size() < 3) {
                      return ans;
                  }
                  sort(nums.begin(), nums.end());
                  for (int i = 0; i < nums.size() - 2; i ++) {
                      int low = i + 1;
                      int high = nums.size() - 1;
                      while (low < high) {
                          if (nums[i] + nums[low] + nums[high] < target) {
                              ans += high - low;
                              low ++;
                          } else {
                              high --;
                          }
                      }
                  }
                  return ans;
              }
          };
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          22
          23

          # 0454. 四数相加 II (opens new window)

          题目

          给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

          为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 228-2^{28}2282^{28} - 1 之间,最终结果不会超过 2312^{31} - 1 。

          解析

          将四个数组分为两部分处理,使用一个 Hash 表记录 A、B 的和出现的次数,之后遍历 C、D,寻找满足条件的和的次数相加即可。

          代码

          class Solution {
          public:
              int fourSumCount(vector<int>& A, vector<int>& B, vector<int>& C, vector<int>& D) {
                  unordered_map<int, int> record;
                  for (int i = 0; i < A.size(); i ++) {
                      for (int j = 0; j < B.size(); j ++) {
                          record[A[i] + B[j]] ++;
                      }
                  }
                  int ans = 0;
                  for (int i = 0; i < C.size(); i ++) {
                      for (int j = 0; j < D.size(); j ++) {
                          int sum = - C[i] - D[j];
                          if (record.find(sum) != record.end()) {
                              ans += record[sum];
                          }
                      }
                  }
                  return ans;
              }
          };
          
          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          15
          16
          17
          18
          19
          20
          21
          Last Updated: 2023-01-28 4:31:25