leetcode 18. 4Sum题解

题目地址

这题和3sum类似,思路也是一样的,只是在外层循环外再套一个一样逻辑的循环

但是,如果单纯的依葫芦画瓢,效率只能超过80%,因为第二层循环的减枝可以有效提高效率,因此我们通过适当减枝来优化算法

class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        List<List<Integer>> ans = new LinkedList<List<Integer>>();
        int i = 0;
        Arrays.sort(nums);
        while(i < nums.length) {
        	while(i - 1 >= 0 && i < nums.length && nums[i-1] == nums[i]) {
        		i ++;
        	}
        	int j = i + 1;
        	while(j < nums.length - 2) {
        		while(j - 1 > i && j < nums.length - 2 && nums[j - 1] == nums[j]) {
        			j ++;
        		}
                int ij = nums[i] + nums[j] ; //speed up
        		if(j >= nums.length - 2 || ij + nums[j+1]+nums[j+2] > target) break;
        		if(ij + nums[nums.length - 2] + nums[nums.length - 1] < target) {
        			j ++;
        			continue;
        		}
        		int k = j + 1;
        		int p = nums.length - 1;
        		while(k < p) {
        			int sum = ij + nums[k] + nums[p];
        			if(sum == target) {
        				LinkedList<Integer> temp = new LinkedList<Integer>();
        				temp.add(nums[i]);
        				temp.add(nums[j]);
        				temp.add(nums[k]);
        				temp.add(nums[p]);
        				ans.add(temp);
        				k ++;
        				while(k < p && nums[k - 1] == nums[k]) {
        					k ++;
        				}
        				p --;
        			}else if(sum < target) {
        				k ++;
        			}else {
        				p --;
        			}
        		}
            	j ++;
        	}
            i ++;
        }
        return ans;
    }
}

深度优先搜索

我们可以根据3sum和4sum归纳出N sum的一般方法,很显然,最终走向两数之和,在此之前都是从小到大开始试探。

我们的策略就是:

1、	判断当前有无可能无解
		·长度不足够?
		·最小的可能和大于目标?
		·最大的可能和小于目标?
	满足任意一个均无解
2、	是否只需求两数和?
	否,转3;
	是:首尾遍历求满足要求的结果,添加到结果集,并注意重复问题
	结束
3、从指定的头开始遍历数组,当遍历到未处理过等值的数据时
		·假定该数据有解,添加到结果集,
		·递归调用自身,问题转化为该数据下一个开始到结尾是否存在n-1个数和为target - nums[i]
		·假设结束,弹出结果集最后一个元素


class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
	    return Sum(nums, 4, target);
	}
	
	private List<List<Integer>> Sum(int[] nums, int n, int target) {
		List<List<Integer>> res = new ArrayList<List<Integer>>();
	    if(nums.length < n) return res;
	    Arrays.sort(nums);
	    NSum(nums, 0, n, target, res, new ArrayList<Integer>());
	    return res;
	}
	
	private void NSum(int[] nums, int start, int n, int target, List<List<Integer>> res, List<Integer> cur) {
		if(nums.length - start < n ||
				nums[start] * n > target || 
				nums[nums.length - 1] * n < target) {
			return;
		}
		if(n == 2) {
			int i = start;
			int j = nums.length - 1;
			while(i < j) {
				int sum = nums[i] + nums[j];
				if(sum == target) {
					cur.add(nums[i]);
					cur.add(nums[j]);
					res.add(new ArrayList<Integer>(cur));
					cur.remove(cur.size() - 1);
					cur.remove(cur.size() - 1);
					i ++;
					j --;
					while(i < j && nums[i] == nums[i - 1]) i ++;
					while(i < j && nums[j] == nums[j + 1]) j --;
				}else if( sum < target) {
					i ++;
				}else {
					j --;
				}
			}
			return ;
		}
		
		for(int i = start; i <= nums.length - n; i ++) {
			if(i == start || nums[i - 1] != nums[i]) {
				cur.add(nums[i]);
				NSum(nums, i + 1, n - 1, target - nums[i], res, cur);
				cur.remove(cur.size() - 1);
			}
		}
	}
}

原思路地址

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值