目录
背景
解题思路
基本问题
衍生问题
三数之和的题目和题目是求解一个数组中满足三数之和等于0的数组的个数。
一般变形有以下几种:
1、求解三数之和等于某个固定目标值的三元数组
2、求解四数之和等于某个固定目标值的四元数组
3、求解与某个目标值最为接近的三元数组
三数之和问题的一般套路是排序+双指针法。四元数组解法一般是在三元数组解法基础上套上一层循环。因此这篇主要就详细套路三元数组和问题。
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != 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] 。
注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
思路:
1、需要先对数组进行排序,因为考察的不是排序算法,所以可以调用函数直接排序(如果想自己写也是可以的),以数组[-1,0,1,2,-1,-4]举例子。
排序后:
2、准备3个指针
【指针I】从数组的头遍历到数组的尾部。【指针L】从【指针I】+ 1的位置开始,【指针R】从数组的尾部开始。
最开始的三指针位置:
【指针I】是最外层循环,从数组头部依次遍历到数组尾部
【指针L】运动轨迹是从【指针I】下一个位置开始向右滑动,直到遇到【指针R】
【指针R】运动轨迹是从 数组尾部开始向左滑动,直到遇到【指针L】
注意,三个指针不能重叠,指向不同的数,且【指针I】< 【指针L】< 【指针R】
3、三指针移动标准:
a、 如果三指针指向的数据和 = 0; 收集此时的答案。并且【指针L】+1,【指针R】-1;
b、如果三指针指向的数据和 > 0,说明此时的答案偏大,把【指针R】-1;
c、如果三指针指向的数据和 < 0,说明此时的答案偏小,把【指针L】+1
d、左右指针重合或者交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1
下面将展示移动过程:
图I
指针交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1
指针交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1
下面的过程不再重复展示。
Java代码:
class Solution {
public List> threeSum(int[] nums) {
List> result = new ArrayList<>();
Arrays.sort(nums);
for(int i=0; i list = new ArrayList<>();
for(int k=0; k
Python代码
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
res = []
nums = sorted(nums)
for i in range(0, len(nums)):
a = nums[i]
left = i + 1
right = len(nums) - 1
while left < right:
target = a + nums[left] + nums[right]
if target == 0:
arr = [a, nums[left], nums[right]]
if arr not in res:
res.append(arr)
left += 1
right -= 1
elif target < 0:
left += 1
else:
right -= 1
return res
给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。
返回这三个数的和。
假定每组输入只存在恰好一个解。
示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
示例 2:
输入:nums = [0,0,0], target = 1
输出:0
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104
思路:
1、在基础问题的基础上准备两个变量,minClose 和maxClose, 意思是比target小且最接近target的数以及比target大且最接近target的数
三指针移动标准:
a、 如果三指针指向的数据和 = target ,返回target,终止程序
b、如果三指针指向的数据和 > target,说明此时的答案偏大,把【指针R】-1,并且与maxClose做比较,如果此时的值更接近target,更新maxClose
c、如果三指针指向的数据和 < target,说明此时的答案偏小,把【指针L】+1,并且与minClose做比较,如果此时的值更接近target,更新minClose
d、左右指针重合或者交错,【指针I】+1,【指针L】= 【指针I】+1,【指针R】= length-1
e、最终比较minClose和maxClose哪个更接近target
Java代码
class Solution {
public int threeSumClosest(int[] nums, int target) {
int minClose = Integer.MIN_VALUE;
int maxClose = Integer.MAX_VALUE;
Arrays.sort(nums);
if(nums[0]+nums[1]+nums[2]>=target){
return nums[0]+nums[1]+nums[2];
}
if(nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3]<=target){
return nums[nums.length-1] + nums[nums.length-2] + nums[nums.length-3];
}
for(int i=0; iminClose){
minClose = tmp;
}
}else if(tmp>target){
right --;
if(tmp
Python代码
class Solution(object):
def threeSumClosest(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
minClose = - (1<<31)
maxClose = 1<<31
nums = sorted(nums)
if nums[0] + nums[1] + nums[2] >= target:
return nums[0] + nums[1] + nums[2]
if nums[-1] + nums[-2] + nums[-3] <= target:
return nums[-1] + nums[-2] + nums[-3]
for i in range(0, len(nums)):
left = i + 1
right = len(nums) - 1
while left < right:
tmp = nums[i] + nums[left] + nums[right]
if tmp < target:
left += 1
if tmp > minClose:
minClose = tmp
elif tmp > target:
right -= 1
if tmp < maxClose:
maxClose = tmp
else:
maxClose = target
minClose = target
return target
return minClose if abs(target-minClose) < abs(target-maxClose) else maxClose
衍生问题2四数之和
解题思路:
1、在三数之和的基础上再添上一层循环
2、由于代码不过,对于数据状况特别差的两种情况做额外处理,如果target>0 且 nums中的值都<0,则没有满足要求的组合。如果target<0 且nums中的值都>0,也没有满足要求的组合
Java代码:
class Solution {
public List> fourSum(int[] nums, int target) {
List> result = new ArrayList<>();
Arrays.sort(nums);
if(target>0){
boolean flg = false;
for(int i=0; i0){
flg = true;
}
}
if(!flg){
return result;
}
}
if(target<0){
boolean flg = false;
for(int i=0; i> result){
for(int idx=start+1; idx resTmp = new ArrayList<>();
resTmp.add(nums[start]);
resTmp.add(nums[idx]);
resTmp.add(nums[left]);
resTmp.add(nums[right]);
if(tmp==target){
if(!result.contains(resTmp)){
result.add(resTmp);
}
left ++;
right --;
}else if(tmp>target){
right --;
}else {
left ++;
}
}
}
}
}
Python代码:
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
result = []
nums = sorted(nums)
if target > 0:
flg = False
for i in range(len(nums)):
if nums[i] > 0:
flg = True
break
if not flg:
return result
if target < 0:
flg = False
for i in range(len(nums)):
if nums[i] < 0:
flg = True
break
if not flg:
return result
for i in range(len(nums)):
self.process(nums, target-nums[i], i, result)
return result
def process(self, nums, target, start, result):
for idx in range(start+1, len(nums)):
left = idx + 1
right = len(nums) - 1
while left < right:
tmp = nums[idx] + nums[left] + nums[right]
resTmp = [nums[start], nums[idx], nums[left], nums[right]]
if tmp == target:
if resTmp not in result:
result.append(resTmp[:])
left += 1
right -= 1
elif tmp > target:
right -= 1
else:
left += 1