题目地址
这题和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);
}
}
}
}