[leetcode] 15. 三数之和
此题相当恶心,多次超时
暴力是O(N^3),明显不会过,不用考虑。
比较好一点的思路是,a+b = -c,我们可以考虑用hash表存下来每个数字是否出现以及出现的次数,枚举a与b,然后看看此时-(a+b)是否存在。O(N^3),但是,仍然超时。
至此我是想不到更优的思路了,于是开始搜别人的题解
大部分人能过得思路是,首先将数组排序,然后枚举c,采用双指针法:i,j分别指向数组中第c+1个数,与最后一个数,
if (num(i) + num(j)) < -c ,说明此时需要更大一点的数,则i++;
if (num(i) + num(j)) > -c ,说明此时需要更小一点的数,则j++;
if ((num(i) + num(j)) == -c,已经找到一个答案,注意当前c循环下可能还会有其它答案,应该继续寻找,而不是break去枚举下一个c,如下样例:
输入:
[-2,0,1,1,2]
预期:
[[-2,0,2],[-2,1,1]]
按道理来说,此时应该能过了,可是还有一个1个测试用例超时 = =,可能c艹能过,java过不了吧
其实可以处理一些剪枝,在符合条件的答案中,一个等式里同样的数字不会出现超过2次,0不会出现超过3次,
所以我们可以把输入的nums处理一下,把出现3次以上的数字统统过滤。
AC代码:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Map<Integer, Integer> mp = new HashMap<>();
List<List<Integer>> ans = new ArrayList<>();
List<Integer> numList = new ArrayList<>();
for (int num : nums) {
if (mp.get(num) == null || mp.get(num) < 3) {
numList.add(num);
if (null != mp.putIfAbsent(num, 1))
mp.put(num, mp.get(num) + 1);
}
}
numList.sort(Integer::compareTo);
for (int k = 0; k < numList.size(); k++) {
int i = k + 1, j = numList.size() - 1;
int target = -(numList.get(k));
while (i < j) {
if (i == k) {
i++;
continue;
} else if (j == k) {
j--;
continue;
}
int now = numList.get(i) + numList.get(j);
if (now == target) {
List<Integer> tmp = new ArrayList<>();
tmp.add(numList.get(i));
tmp.add(numList.get(j));
tmp.add(-target);
tmp.sort(Integer::compareTo);
ans.add(tmp);
if (numList.get(j - 1) == numList.get(j)) {
j--;
} else {
i++;
}
} else {
if (now > target) {
j--;
} else {
i++;
}
}
}
}
return ans.stream().distinct().collect(Collectors.toList());
}
}