LeetCode 15 3Sum

本文介绍了一种高效算法来解决在给定数组中查找和为零的三元组问题,通过排序和双指针技巧优化时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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:

  • Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
  • 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)

解题思路:这一道题是2-sum问题的延续,几乎所有人都能想到O(n^3)复杂度的三重循环的判断方法,显然对于较大的序列,三重循环的时间复杂度难以忍受。思路与解决2-sum的方法一致,首先将序列排序,然后拿出一个定值,在该值的基础上,设置两个指针start和end分别从序列的开头和末尾进行遍历判断,若计算结果大于0,则末尾左移。若计算结果小于0,则开头右移。

在上述基础之上,已经可以解决该问题,但是重复性的工作并没有彻底的消除。另外,结果的重复性也没有消除。因此,还需要对下标做一些计算处理。
(1).对于结果已经处于升序状态是有原因的,当我们开始遍历的时候,代码如下:
       int start =i+1;
        int end = len-1;
int s = nums[i]
;
这样的遍历方式保证了结果按升序排列,可能你会担心会漏掉一些结果,实际上这样的担心是多余的,那些start在 s之前的情况实际上已经被s start end这种情况所包含,因此担心是多余的。
(2).为了解决重复性的问题,当完成一次==0的判断之后,对于nums[start]、nums[end]若有重复值,则让其指针分别++和--。
(3)在第一层循环,对于重复的s值,应该将其跳过,否则会有重复的序列。不必要担心会漏解,因为在前一次循环已经把所有解都计算出来了。
(4).为了保证没有漏解,比如 0、0、-1、-1、0序列,在完成第一判断得到{0,0,0}之后,并完成(2)以后,进行start++、end--操作。

代码如下:
    public List<List<Integer>> threeSum(int[] nums) {
    	List<List<Integer>> lists=new ArrayList<List<Integer>>();
    	if(nums.length<=2)return lists;
    	Arrays.sort(nums);
    	int len =nums.length;
    		for (int i = 0; i < len-2; i++) {//len-2已经包含所有情况
    			if(i>0&&nums[i]==nums[i-1])continue;//这里是i-1与i的判断因为for循环已经i++了
    	    	int start =i+1;
    	    	int end = len-1;
				int s = nums[i];
		    	while(start<end){
		    	   	Integer[] arr = new Integer[3];
					int re = s +nums[start]+nums[end];
					if(re>0){
					end--;	
					}else if(re<0){
					start++;
					}else{
						arr[0]=s;
						arr[1]=nums[start];
						arr[2]=nums[end];
						 ArrayList<Integer> tr = new ArrayList<Integer>();
						 tr.add(arr[0]);
						 tr.add(arr[1]);
						 tr.add(arr[2]);
						 lists.add(tr);	
						 while (start < end && nums[start] == nums[start+1]) start++;  
			               while (start < end && nums[end] == nums[end-1]) end--;  
							start++;//对于同一个s  可能有多个适配的情况; 这个如果放在重复判断之前 会导致漏解比如 -2 0 1 1 2
							end--;
					}	
		    	}
			}
		      return lists; 
    }



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值