给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
审题:
查询数组中的三个数字加起来结果为0.
思考:
循环遍历三次,最笨的方式。
解题:
解法一:
// 最笨的办法,循环遍历三次。
public List<List<Integer>> threeSum_0(int[] num) {
List<List<Integer>> ret = new LinkedList<List<Integer>>();
for (int i = 0; i < num.length - 2; i++) {
for (int j = i + 1; j < num.length - 1; j++) {
for (int k = j + 1; k < num.length; k++)
if (num[i] + num[j] + num[k] == 0) {
// List 是一种很有用的数据结构,如果需要将一个数组转换为 List 以便进行更丰富的操作的话,可以这么实现:
ret.add(Arrays.asList(num[i], num[j], num[k]));
}
}
}
return ret;
}
解法二:
//使用map,循环两次,将两个值作为数组存入map的value。key是0-第一个值-第二个值,
//每次循环的时候,都判断第二个值是否是map的key,如果是,就是符合条件的,取出map中的两个值,还有key 就是一个结果。
public List<List<Integer>> threeSumII(int[] num){
List<List<Integer>> rets = new LinkedList<List<Integer>>();
Map map = new HashMap<Integer, List>();
for(int i = 0;i<num.length-2;i++) {//第一次遍历,-2后边至少有两个数字。
for(int j = i + 1; j < num.length - 1; j++) {//第二次遍历,
//判断里层循环结果是否是key,如果是则是结果
if(map.get(num[j])!=null) {
//第一个数字,(Integer)((List)map.get(num[j])).get(0)
//第二个
rets.add(Arrays.asList((Integer)((List)map.get(num[j])).get(0),(Integer)((List)map.get(num[j])).get(10),num[j]));
}else {//如果不是,继续put到map
map.put(0-num[i]-num[j], Arrays.asList(num[i],num[j]));
}
}
}
return rets;
}
第三中方法:双向查找。
// 循环一遍的方式。threeSumIII,循环第一个数字,后两个数字通过两端寻找。双向扫描
public List<List<Integer>> threeSumIII(int[] num) {
List<List<Integer>> res = new LinkedList<List<Integer>>();
// 对num排序。
Arrays.sort(num);
for (int i = 0; i < num.length - 2; i++) {// 循环
//因为即使出现-1,-1,-1,2这种情况,第一次-1出现的时候,也会将结果记录,之后只需要一个-1和后边数字求和判断即可。
if (i == 0 || (i > 0 && num[i] != num[i + 1])) {//如果两个数字相同就需要跳过,
// lo下一个要遍历的数字的下标(左边);;hi数组的长度(右边);sum第二和第三数字的和。
int lo = num[i+1],hi = num.length-1,sum = 0-num[1];
while(lo<hi) {
if(num[lo]+ num[hi] ==sum) {//符合条件
res.add(Arrays.asList(num[i], num[lo], num[hi]));//符合标准。
while(lo < hi &&num[lo] == num[lo+1]) {//如果后边有数字相同,同样也需要跳过。
lo++;
}
while(lo<hi&&num[hi] == num[hi-1]) {
hi--;
}
//排除重复后,将两边同时移动
// 然后第二个第三个数字都要移位,标准的双向扫描,
lo++;
hi--;
}else if(num[lo]+ num[hi] >sum) {//结果大,右边左移。
hi--;
}else {//结果小,左边右移
lo++;
}
}
}
}
return res;
}
知识点:
// List 是一种很有用的数据结构,如果需要将一个数组转换为 List 以便进行更丰富的操作的话,可以这么实现:
Arrays.asList(num[i], num[j], num[k])
String[] myArray = { "Apple", "Banana", "Orange" };
List<String> myList = Arrays.asList(myArray);