LeetCode进阶之路(3Sum)

Given an array S of n integers, are there elements abc in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note: The solution set must not contain duplicate triplets.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is:
[
  [-1, 0, 1],
  [-1, -1, 2]
]

题目:给一个数组,求三个和为0的组合;

思路一:最简单的就是暴力解法,把所有的组合都列出来,算出结果。这种方法肯定不是题目想要的解法,但是还是尝试了编写,也把这份代码贴上。

public List<List<Integer>> threeSum(int[] sum) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
		
		for(int i = 0; i < sum.length; i++) {
			for(int j = i+1; j< sum.length;j++) {
				for(int k = j+1 ; k < sum.length;k++) {
					if(isZero(sum[i], sum[j], sum[k])){
						List<Integer> listNum = new ArrayList<Integer>();
						listNum.add(sum[i]);
						listNum.add(sum[j]);
						listNum.add(sum[k]);
						Collections.sort(listNum, new Comparator<Integer>() {
							public int compare(Integer arg0, Integer arg1){
								return arg0.compareTo(arg1);
							}
						});
						if(!list.contains(listNum)){
							list.add(listNum);
						}
						
					}
				}
			}
		}
		return list;
    }
    
    public boolean isZero(int n1, int n2, int n3) {
		if(n1+n2+n3 == 0) {
			return true;
		}else {
			return false;
		}
	}

思路二:3sum是求三个和为0,那就可以转换成2sum(和为另一个的相反数)。先考虑2sum如何做,一般解法是O(n^2),所以不能简单的遍历所有结果,需要舍弃一些组合,那就先把数组排个序,这样好找规律。一般我考虑是不是可以头尾向中间循环,这样复杂度会小一些,当两个和为0时即为目标组合。

public static List<List<Integer>> twoSum(int[] num) {
		List<List<Integer>> list = new ArrayList<List<Integer>>();
		Arrays.sort(num);
		int left = 0;//左指针
		int right = num.length-1;//右指针
		while(left < right) {
			if((num[left] + num[right])==0){
				List<Integer> listNum = new ArrayList<Integer>();
				listNum.add(num[left]);
				listNum.add(num[right]);
				list.add(listNum);
				while(left < right && num[left] == num[left+1])left++;//排除和num[left]下一位相同的数
				while(left < right && num[right] == num[right-1])right--;
				left++;
				right--;
			} else if(num[left] + num[right] < 0) {
				left++;//偏小,左端增加
			} else{
				right--;//偏大,右端增加
			}
		}
		return list;
	}

 回到3sum,就可以先固定一个数,然后另外求两个数的组合为这个数的相反数。 
 

List<List<Integer>> list = new ArrayList<List<Integer>>();
	public static  List<List<Integer>> threeSum(int[] num) {
		if(num == null || num.length<3) return list;
		
		Arrays.sort(num);
		for(int i = 0;i < num.length;i++) {
			int left = i+1;
			int right = num.length-1;
			twoSum(num, left, right, num[i]);
		}
		return list;
	}
	public static List<List<Integer>> twoSum(int[] num, int l, int r, int n) {
		
		Arrays.sort(num);
		int left = l;//左指针
		int right = r;//右指针
		while(left < right) {
			if((num[left] + num[right]) + n ==0){
				List<Integer> listNum = new ArrayList<Integer>();
				listNum.add(num[left]);
				listNum.add(num[right]);
				listNum.add(n);
				Collections.sort(listNum);
				if(!list.contains(listNum)){
					list.add(listNum);
				};//排除重复的listNum
				while(left < right && num[left] == num[left+1])left++;//排除和num[left]下一位相同的数
				while(left < right && num[right] == num[right-1])right--;
				left++;
				right--;
			} else if(num[left] + num[right] + n < 0) {
				left++;//偏小,左端增加
			} else{
				right--;//偏大,右端增加
			}
		}
		return list;
	}
but!!!这种方式也超时了,想破脑袋也没发现哪里有问题,没办发,百度后发现是listNum排序这段代码的问题,从一开始就应该排除掉相同的数字,因为这个数组是有序的,只需前后比较即可排除。不同之处以标红。

List<List<Integer>> list = new ArrayList<List<Integer>>();
    public List<List<Integer>> threeSum(int[] num) {
		if(num == null || num.length<3) return list;
		Arrays.sort(num);
		for(int i = 0;i < num.length-2;i++) {
			int left = i+1;
			int right = num.length-1;
<span style="white-space:pre">			</span>if (i > 0 && num[i] == num[i-1]) continue; 
			twoSum(num, left, right, num[i]);
		}
		return list;
	}
	public List<List<Integer>> twoSum(int[] num, int l, int r, int n) {
		int left = l;//左指针
		int right = r;//右指针
		while(left < right) {
			if((num[left] + num[right]) + n ==0){
				List<Integer> listNum = new ArrayList<Integer>();
				listNum.add(num[left]);
				listNum.add(num[right]);
				listNum.add(n);
				// Collections.sort(listNum);
				// if(!list.contains(listNum)){
				// 	list.add(listNum);
				// };</span><span style="color:#333333;">
				list.add(listNum);
				while(left < right && num[left] == num[left+1])left++;//排除和num[left]下一位相同的数
				while(left < right && num[right] == num[right-1])right--;
				left++;
				right--;
			} else if(num[left] + num[right] + n < 0) {
				left++;//偏小,左端增加
			} else{
				right--;//偏大,右端增加
			}
		}
		return list;
	}</span>




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值