思路: two pointer。这题其实是3sum的变种。但是我们不可以他说要求4sum,我们就简单在3sum的代码外面再套一层循环。这不是长久之计,我们面试可能会被问到6sum,7sum。。。所以这题的主旨是要我们解决ksum的问题。这边其实思路还是two pointer,只不过我们要用到recursion。base case这边是2sum。其实就相当于,比方说要求5sum,那么就recursion,先4sum,再3sum,最后到2sum。这时候突然发现我们碰到base case了(我们可以直接解决的最小情况),然后再从底往上一个个的返回上去,得到最后的结果。这题还要注意的是不能有重复的答案,所以我们可以先得到所有的答案,然后sort,sort之后一样的就不要。我觉得这题还挺经典的,可是我做这题的时候状态不是特别好,代码也是看了答案才写出来的,所有这题我打算标记为attempted,以便之后复盘好好再做一遍。下面直接给出代码:
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
Arrays.sort(nums);
return kSum(nums,0,4,target);
}
private List<List<Integer>> kSum(int[] nums, int start, int k, int target){
List<List<Integer>> res = new ArrayList<>();
Set<List<Integer>> set = new HashSet<>();
if(start == nums.length || k * nums[0] > target || k * nums[nums.length - 1] < target){return res;}
if(k == 2){return twoSum(nums,start,target);}
for(int i= start; i < nums.length; i++){
int subStart = i + 1;
int subK = k - 1;
int subTarget = target - nums[i];
List<List<Integer>> subRes = new ArrayList<>();
subRes = kSum(nums,subStart,subK,subTarget);
for(int j = 0; j < subRes.size(); j++){
subRes.get(j).add(nums[i]);
//subRes.get(j).sort();
Collections.sort(subRes.get(j));
set.add(subRes.get(j));
}
}
res.addAll(set);
return res;
}
private List<List<Integer>> twoSum(int[] nums, int start, int target){
List<List<Integer>> res = new ArrayList<>();
int left = start, right = nums.length - 1;
while(left < right){
List<Integer> list = new ArrayList<>();
if(nums[left] + nums[right] < target || (left > start && nums[left] == nums[left - 1])){
left++;
}else if(nums[left] + nums[right] > target || (right < nums.length - 1 && nums[right] == nums[right + 1])){
right--;
}else{
list.add(nums[left]);
list.add(nums[right]);
res.add(list);
left++;
right--;
}
}
return res;
}
}
总结:
- two pointer适用于一切sorted array
- list 排序 Clooections.sort(list);
- convert set to list: list.addAll(set);