Leetcode刷题笔记——n-sum问题

2Sum:

题目描述:

给定一个整型数组nums,一个target,从数组中找出a、b,使得a+b=target;并且假定数组中只有一对满足条件的a、b

原始思路:

用两个for循环遍历数组,找出结果,时间复杂度为O(n2)

优化思路:

使用hash表,建立HashMap<Integer, Integer> map,键值对为<nums[i],i>。遍历数组nums,对每个数nums[i],查询hash表中是否有key等于target-nums[i]的记录,若有,则找到;否则,将num[i]和下标i存入hash表。因为hash表的查找时间复杂度可以看作是O(1),所以算法时间复杂度就降为O(n)了。

 

3Sum:

题目描述:

给定一个整型数组nums,从数组中找出所有不重复的[a,b,c],使得a+b+c=0

原始思路:

3个for循环,但是超时了

优化思路:

使用双指针。首先将数组排序(防止重复),然后遍历数组,在每个位置i,设置双指针,左指针指向位置i+1,右指针指向位置nums.length-1,计算三个位置数之和,若等于0,则将三数位置下标加入结果集,左指针右移,右指针左移;若大于0,则右指针左移;若小于0,则左指针右移,直到左右指针相遇。遍历完数组,找到所有符合条件的[a,b,c]。为防止重复结果,若指针移动的下一个位置上的数与上一个位置上的数字相等,继续移动一位。这种方法的时间复杂度可以控制在O(n2)。

 

3SumClosest:

题目描述:

给定一个整型数组nums,一个target,从数组中找出3个数之和sum,使得sum与target差的绝对值最小

思路:

与3Sum类似,使用双指针。

 

4Sum:

题目描述:

给定一个整型数组nums,一个target,从数组中找出所有不重复的四元数组[a, b, c, d],使得a+b+c+d = target

思路:

分解,将4Sum分解成3Sum再分解成2Sum,2Sum可以使用Hashmap或者双指针,从而将时间复杂度控制在O(n3)。实际代码实现中要注意避免重复的问题,并且可以使用一些判断条件(如:因为数组为升序,如果当前nums[i]*4 > target,就可以直接break了)进行速度优化。

具体实现:

public List<List<Integer>> fourSum(int[] nums, int target){
List<List<Integer>> res = new ArrayList<>();
// 数组为空或长度小于4,返回
if(nums == null || nums.length < 4)
return res;
//排序
Arrays.sort(nums);
//数组太大或数组太小,返回
if(nums[0]*4 > target || nums[nums.length-1]*4 < target) return res;

for(int i=0; i<nums.length-3; i++){
//注意判断条件不能是nums[i+1] == nums[i],因为单组结果中可以出现重复的数字
if(i != 0 && nums[i-1] == nums[i]) continue; //避免重复

if(nums[i]*4 == target){
if(nums[i+3] == nums[i]){
res.add(Arrays.asList(nums[i], nums[i], nums[i], nums[i]));
return res;
}
}

if(nums[i] + 3*nums[nums.length-1] < target) continue; //nums[i]太小

if(nums[i] * 4 > target) return res; //nums[i]太大

threeSumForFourSum(nums, target-nums[i], i+1, res, nums[i]);
}
return res;

}

public void threeSumForFourSum(int[] nums, int target, int start, List<List<Integer>> res, int z1){

if(3*nums[start] > target || 3*nums[nums.length-1] < target) return;

for(int i=start; i<nums.length-2; i++){

if(nums[i]*3 > target) return; //过大

if(nums[i] + nums[nums.length-1]*2 < target) continue; //过小

if(i != start && nums[i-1] == nums[i]) continue; //避免重复

if(3*nums[i] == target){
if(nums[i+2] == nums[i]){
res.add(Arrays.asList(z1,nums[i],nums[i],nums[i]));
return;
}
}
twoSumForFourSum(nums, target-nums[i], i+1, res, z1, nums[i]);
}

}

public void twoSumForFourSum(int[] nums, int target, int start, List<List<Integer>> res, int z1, int z2){

if(start == nums.length-1) return;

if(nums[start] *2 > target) return;

HashMap<Integer, Integer> map = new HashMap<>();
for(int i= start; i<nums.length; i++){
if(i != start && nums[i-1] == nums[i]) continue; //避免重复
if(i!= nums.length-1 && 2*nums[i] == target){
if(nums[i+1] == nums[i]){
res.add(Arrays.asList(z1,z2,nums[i],nums[i]));
}
}
int cut = target-nums[i];
if(map.containsKey(cut)){
res.add(Arrays.asList(z1,z2,cut,nums[i]));
continue;
}
map.put(nums[i],i);
}
}

 

转载于:https://www.cnblogs.com/yingying7/p/11044215.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值