本篇将「求和问题」梳理一遍。求和问题是指一类从数组中找出 K 个数满足其和为给定整数的问题。
1 Two Sum
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
数组无序
如果使用 Brute-Force 方法,时间复杂度是 $O(n^2)$。
时间复杂度和看空间复杂度均为 $O(n)$ 的方法是建立一个 Hash Table。对于数组中的每一个元素 x
,如果对应的 target - x
在 Hash Table 中,则组成符合条件的一对整数。
1 | public int[] twoSum(int[] numbers, int target) { |
数组有序
二分查找
二分查找法在查找 target - x
时应用二分查找,可以将 Hash Table 方法的 $O(n)$ 空间复杂度降为 $O(1)$,但时间复杂度上升——$O(n \log{n})$ runtime, $O(1)$ space。该方法不是最优方法。
双指针
数组已经升序排列。假定在某一时刻,左右两个指针分别指向 A[i]
和 A[j]
,那么两者之和有以下三种情况:
A[i] + A[j] > target
:需要将j
左移以使A[i] + A[j]
减小;A[i] + A[j] < target
:需要将i
右移以使A[i] + A[j]
增大;A[i] + A[j] == target
:即为答案,将i
和j
同时移动。
可以证明不存在其他情况。
1 | public int[] twoSum(int[] numbers, int target) { |
2 3-Sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
1
2
3
4
5
6
7 For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
可以将求解 2-Sum 问题的方法应用于求解 3-Sum。由于本题简化了一步,即设定 target = 0
,因此从(已排序的)数组中挑一个数 x
,只需在剩下的 $n-1$ 个数中找出所有和为 0 - x
两个数即可(可能有多组)。
应用 2-Sum 解法需要额外考虑一点就是重复结果的问题。题目要求返回的集合不能包括重复的「三元组」。因此,在外围循环中遍历每一个元素 A[i]
时,只需在 i
以后的数组上应用 2-Sum 方法,即表示左边指针位置的 low = i + 1
。
此外,对形如 [-4, -1, -1, 0, 1, 2]
的数组,当迭代到第二个 -1
时,可以直接跳过,因为(如果执行检索将会)得出的结果已经包含在计算第一个 -1
时得到的结果集中了。
1 | public List<List<Integer>> threeSum(int[] num) { |
3 3-Sum Closest
Given an array
S
ofn
integers, find three integers inS
such that the sum is closest to a given number,target
. Return the sum of the three integers. You may assume that each input would have exactly one solution.
1
2 For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
只需对上述 3-Sum 解法略作修改,在指针移动时对三者之和进行判断即可。时间复杂度是 $O(n^2)$。
1 | public int threeSumClosest(int[] nums, int target) { |
4 4-Sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note: The solution set must not contain duplicate quadruplets.
1
2
3
4
5
6
7
8 For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0.
A solution set is:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
类似地,借助 2-Sum 和 3-Sum 可以解决 4-Sum 问题。简单来讲,依然是遍历有序数组元素 A[i]
时,对 A[i+1, n-1]
应用 3-Sum 算法。
LeetCode 讨论板块上的帖子 7ms java code win over 100% - LeetCode Discuss 给出了一种效率极高的方法。其中跳过了许多不可能满足条件的情况,避免了不需要的计算。例如
i > 0 && z == A[i - 1]
时,跳过检查;A[i] + 3 * A[n - 1] < target
时,i
太小以至于不可能在剩余数组中找出满足条件的三元组;4 * A[i] > target
时,i
太大;4 * A[i] == target
时,只有当「从A[i]
开始连续4项均相等」时才满足,其他情况不可能;
除上述以外的其他情况,都执行检查。
具体代码参考帖子。