nsum问题是面试中经常会问到的题目,LeetCode上关于nsum的问题有
这里将介绍这四个问题的解答方法,
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.
Example:
Given nums = [2, 7, 11, 15], target = 9,
Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].
————————
这道题直接用两个循环暴力解即可,对数组进行遍历查找两个数之和,时间复杂度是O(n^2),在题目允许范围内
class Solution {
public int[] twoSum(int[] nums, int target) {
int tsum[]=new int[2];
for(int i=0;i<nums.length-1;i++)
{
for(int j=i+1;j<nums.length;j++)
{
if((nums[i]+nums[j])==target)
{
tsum[0]=i;
tsum[1]=j;
return tsum;
}
}
}
return tsum;
}
}
3Sum
Given an array nums
of n integers, are there elements a, b, c in nums
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.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
—————————
这道题暴力解的话时间复杂度是O(n^3),一般情况下肯定会超时的,所以这里对题目分析一下,如果降低时间复杂度。
当然,在对数组题没有什么思路的情况下,在题目对顺序没有要求的话,可以先将数组进行排序,方便之后的操作。对这道题的数组先排序。
Arrays.sort(nums);
同样,我们可以把这个问题转化为2sum的问题,但是外层循环每一次查找的target变成了需要计算的总值(这里是0)减去数组中的每个数,即为
target=0-nums[i]
这里需要注意的是,如果数组中存在两个相等的值,那如果对这两个值都进行查找,得到的结果肯定是相同的,为了避免这种情况,应该加入判断语句
if(i>0&&nums[i]==nums[i-1])
{
continue;
}
内层循环查找的方式为从两端向中间查找,不断逼近所需的target,当两端数之和小于target时,即
nums[left]+nums[right]+nums[i]<0
此时需要将left++,使得更接近target。
反之如果大于target,需要将right--.
如果等于的话则存入输出的List中,同时将left和right向中间移动。这里还需要判断如果移动到了相同的left/right的值,为了避免得到重复的结果,应该继续移动。
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
因此可以得到如下结果:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> lsi=new ArrayList<>();
for(int i=0;i<nums.length-2;i++)
{
if(i>0&&nums[i]==nums[i-1])
{
continue;
}
int target=-nums[i];
int left=i+1,right=nums.length-1;
while(left<right)
{
if(nums[left]+nums[right]<target)
{
left++;
}
else if(nums[left]+nums[right]>target)
{
right--;
}
else
{
List<Integer> tar=Arrays.asList(-target,nums[left],nums[right]);
lsi.add(tar);
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
}
}
}
return lsi;
}
}
3Sum Closest
Given an array nums
of n integers and an integer target
, find three integers in nums
such that the sum is closest to target
. Return the sum of the three integers. You may assume that each input would have exactly one solution.
Example:
Given array nums = [-1, 2, 1, -4], and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
题目的意思就是,给出一个数组和一个目标值,需要找到3个数,使它们之和最接近这个目标值,并返回这个和。
解题和3Sum差不多,需要注意的只有设置一个变量mm来记录结果,在循环中如果得到的和不等于target,则判断其与mm谁更接近,mm则改为更接近的那个值。
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int mm=nums[0]+nums[1]+nums[nums.length-1];
for(int i=0;i<nums.length-2;i++)
{
if(i>0&&nums[i]==nums[i-1])
{
continue;
}
int targ=target-nums[i];
int left=i+1,right=nums.length-1;
while(left<right)
{
if(nums[left]+nums[right]<targ)
{
if(Math.abs(mm-target)>Math.abs(nums[left]+nums[right]+nums[i]-target))
{
mm=nums[left]+nums[right]+nums[i];
}
left++;
}
else if(nums[left]+nums[right]>targ)
{
if(Math.abs(mm-target)>Math.abs(nums[left]+nums[right]+nums[i]-target))
{
mm=nums[left]+nums[right]+nums[i];
}
right--;
}
else
{
return target;
}
}
}
return mm;
}
}
4Sum
Given an array nums
of n integers and an integer target
, are there elements a, b, c, and d in nums
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.
Example:
Given array nums = [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]
]
同样,我们可以参考3Sum的方法,3Sum是先确定3个数中的1个数,这里利用两层循环确定4个数中的2个数,同时需要考虑重复的情况(这个比较坑)
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
List<List<Integer>> lsi=new ArrayList<>();
for(int i=0;i<nums.length-3;i++)
{
for(int j=i+1;j<nums.length-2;j++)
{
int ta=target-nums[i]-nums[j];
int left=j+1,right=nums.length-1;
while(left<right)
{
if(nums[left]+nums[right]<ta)
{
left++;
}
else if(nums[left]+nums[right]>ta)
{
right--;
}
else
{
List<Integer> tar=Arrays.asList(nums[i],nums[j],nums[left],nums[right]);
lsi.add(tar);
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
while(i<nums.length-4&&nums[i]==nums[i+1])
{
i++;
}
while(j<nums.length-3&&nums[j]==nums[j+1])
{
j++;
}
}
}
}
}
return lsi;
}
}