LeetCode 第一题就是很经典的题目: twoSum
,twoSum
的解法有很多种,最经典的方法就是 排序+双指针
,如果我们掌握了这个核心解法,那么去解 NSum
的问题将会很easy!
划重点 排序+双指针
是我们解决 NSum
的核心思想。
一. twoSum
问题
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/two-sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
这倒提的解法可以看我的 Github Day1120TowNum
由于这道题是让求数组的下标,跟我们要求数组里面的值相加等于target有点出入,所以这里不展开描述了。项目里面提供了两个解法,一个是利用HashMap去解,另一个是利用 排序+双指针
思路去解。
下面我们将题目描述变一下:
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的
值
。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [2, 7]
解决这个问题的核心是使用排序+双指针
:
- 首先对数组进行排序
- 利用双指针,从两端相向相加跟target的值进行比较
问题的关键在于不能重复,假如数组为 [2, 7, 11, 15] ,target = 9
,那么输出 [2,7],[7,2]
就是重复的项,所以我们需要注意将重复的值去掉。
如果数组为[2, 7, 2, 7, 11, 15] ,target = 9
,那么输出的 [2,7],[2,7]
也属于重复的项,同样需要将重复的项去掉。
代码如下:
1 | public static List<List<Integer>> twoSum(int[] nums, int start, int target) { |
这样我们就写出来一个通用的 twoSum
模板了,针对题目变种后,问题将会迎刃而解。
- 时间复杂度: 循环是O(N),排序是O(NlogN),所以整体的时间复杂度是 O(NlogN)
二. 3Sum
问题
题目描述:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
问题上升到 3Sum
,其实我们只有将这个问题转化成 twoSum
,问题就会迎刃而解,怎么转换呢?穷举。我们求三个数的和是 target
,那么也就是说我们可以固定住第一个数,然后去求除第一个数以外的其他数任选两个数的和为 target-num[0]
,依次类推,就是求target-num[i]
的 twoSum
。
所以代码如下:
1 | public static List<List<Integer>> twoSum(int[] nums, int start, int target) { |
- 时间复杂度 排序O(NlogN),
twoSum
O(N),threeSum
里面循环调用twoSum
,所以时间复杂度是 O(NlogN+N*N)=O(N^2)
4Sum
问题
题目描述:
给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决 4Sum
的思路跟解决 3Sum
的思路一样,我们通过穷举将问题转换成 3Sum
,问题就得到了解决。
代码如下:
1 | public static List<List<Integer>> fourSum(int[] nums, int target) { |
- 时间复杂度:
4Sum
循环了3Sum
,所以时间复杂度是 O(N^3)
NSum
问题
5Sum
根据 4Sum
可以得出,4Sum
根据 3Sum
可以得出,3Sum
根据 2Sum
可以得出,所以那就 递归
吧。。。
递归条件
nums ,n,start,target
递归终止条件
n如果小于2则退出递归
所以代码大概的递归框架如下:
1 |
|
我们现在根据递归框架,往代码里面进行填肉:
1 | public static List<List<Integer>> nSum(int[] nums, int n, int start, int target) { |
总结
总结一下:NSum
的核心思想就是 排序+双指针
,当然我们为了求 NSum
,最后用到了递归。虽然方法不是最快的,但是这个思路是最方便解这样的题的。
参考资料
- LeetCode labuladong题解