The idea is to narrow down 4 to 2, by two extra outside loops. The hard part is to avoid duplicated, by three different necessary moves: skip directly by skipping 0 case (-1), skip from second iteration by default pre value to -1 and set it in iterations, skip by a while loop for all pre on both sides(++ and --). Sort is must have before all operations.
Details is to notice the loop condition. And only loop ranges after the current index at outside loop is sufficient!
public class Solution {
public ArrayList<ArrayList<Integer>> fourSum(int[] num, int target) {
if(num == null || num.length < 4){
return new ArrayList<ArrayList<Integer>>();
}
ArrayList<ArrayList<Integer>> results = new ArrayList<ArrayList<Integer>>();
Arrays.sort(num);
for(int s1 = 0; s1 < num.length - 3; s1++){
if(s1 > 0 && num[s1] == num[s1 - 1]){ //Skip 0 case
continue;
}
int curT = target - num[s1];
int preS2 = -1; //record previous position of s2 [0,0,0,0] vs [1, 0, 0, 0, 0] aroused this idea (fail either before)
for(int s2 = s1 + 1; s2 < num.length - 2; s2++){ //Track previous s2 but need to start checkin at the second loop to not touch s1, that is why set pre first... the first iteration skips checks
if( preS2 != -1 && num[s2] == num[preS2]){
continue;
}
preS2 = s2;
int curTarget = curT - num[s2];
int s3 = s2 + 1;
int s4 = num.length - 1;
while(s3 < s4){
if(num[s3] + num[s4] > curTarget){
s4--;
}else if(num[s3] + num[s4] < curTarget){
s3++;
}else{
ArrayList<Integer> result = new ArrayList<Integer>();
result.add(num[s1]);
result.add(num[s2]);
result.add(num[s3]);
result.add(num[s4]);
results.add(result);
while(++s3 < --s4 && num[s3] == num[s3 - 1] && num[s4] == num[s4 + 1]); //Skip duplicates
}
}
}
}
return results;
}
}
没有评论:
发表评论