LeetCode-15-算法-三数之和(中等)

23 篇文章 0 订阅

给你一个包含 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);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值