目录
1.最接近的三数之和
给你一个长度为 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
解释:与 target 最接近的和是 0(0 + 0 + 0 = 0)。
思路
排序+双指针:排序时间复杂度为O(nlogn),双指针遍历O(n),因此整体时间复杂度是O(nlogn),如果是暴力解法是O(n^2),因此优于暴力算法
java
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int minSum = 1_00_0001;
int n = nums.length;
for(int i=0;i<n-2;i++){
//判断左边界
//这里加了优化,如果最左边三个元素和大于target,则后续不用遍历,因为根据数组有序性,其他元素和更是大于target,取当前最小值即可
int curSum = nums[i]+nums[i+1]+nums[i+2];
if(curSum>target){
minSum = Math.abs(target-curSum)<Math.abs(minSum-target)?curSum:minSum;
continue;
}
//判断右边界
//分析同上
curSum = nums[i]+nums[n-1]+nums[n-2];
if(curSum<target){
minSum = Math.abs(target-curSum)<Math.abs(minSum-target)?curSum:minSum;
continue;
}
curSum = nums[i]+nums[i+1]+nums[i+2];
int j=i+1,k=n-1;
curSum = nums[i]+nums[j]+nums[k];
while(j<k){
minSum = Math.abs(target-curSum)<Math.abs(minSum-target)?curSum:minSum;
if(curSum>target){
curSum -= nums[k];
k--;
curSum += nums[k];
}else{
curSum -= nums[j];
j++;
curSum += nums[j];
}
}
}
return minSum;
}
}
时间复杂度: O ( n log n ) O(n \log n) O(nlogn)
空间复杂度: O ( 1 ) O(1) O(1)
2.四数之和
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
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]]
示例 2:
输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
思路
同上一题思路一样,排序加双指针,暴力解法是四层遍历,时间复杂度为O(n4),而双指针时间复杂度为O(n3)
java
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
//先排序
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
for(int i=0;i<n-3;i++){
//这里有小优化,判断当前是否与前一个循环的元素相同,保持每个四元组只有一个
if(i>0&&nums[i]==nums[i-1]){
continue;
}
for(int j=i+1;j<n-2;j++){
//这里同样的优化,目的也是为了保证四元组的唯一性
if(j>i+1&&nums[j]==nums[j-1]){
continue;
}
long remains = (long)target-nums[i]-nums[j];
if(nums[j+1]+nums[j+2]>remains||nums[n-2]+nums[n-1]<remains){
continue;
}
for(int k=j+1,l=n-1;k<l;){
int sum = nums[k]+nums[l];
if(sum==remains){
List<Integer> list = List.of(nums[i],nums[j],nums[k],nums[l]);
ans.add(list);
k++;
while(k<l&&nums[k]==nums[k-1]){
k++;
}
l--;
while(k<l&&nums[l]==nums[l+1]){
l--;
}
}else if(sum<remains){
k++;
}else{
l--;
}
}
}
}
return ans;
}
}
时间复杂度: O ( n 3 ) O(n^3) O(n3)
空间复杂度: O ( 1 ) O(1) O(1)