Leetcode刻意练习04--三数之和

三数之和

在这里插入图片描述
题目:
参数列表:给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?返回值找出所有满足条件且不重复的三元组。

补充知识;

三元组实例化方式

 List<List<Integer>> ans=new ArrayList<>();
    	 //List是一个接口,可以使用ArrayList或LinkedList来实现

三元组添加元素的方式

//第一种方式:
List<Integer> list=new ArrayList();	
    					list.add(nums[i]);
    					list.add(nums[l]);
    					list.add(nums[r]);
    					ans.add(list);
//第二种方式,会比第一种方式耗时短,
//其中Arrays.asList(int,int ~)
//> static <T> List<T>	asList(T... a)
//返回由指定数组支持的固定大小的列表。

ans.add(Arrays.asList(int,int,~))
    			

思路一:
三个for循环。时间复杂度log(n^3)

思路二:
我们由两数之和可以想到运用两个指针。
或者
另一种办法是:数组里的元素存在一个set里,遍历数组,求出partial_target=target-nums[i],然后再set里面寻找partial_target。
但是这样容易会有错误。例如:数组中含有一个12,target=24,p_t=12,在set里面找p_t是可以找到的,但是[[12,12]]并不是我们要的答案,因为12只能被使用一次。
于是我们改进,将数组里的元素不再存入set,而是存入hashset,一并存入的还有元素出现的次数,如果出现的次数大于1,那么该元素可以被使用第二次。

如何在三数之和中使用双指针。
1.sort,排序。
2.从第一个元素 nums[0] 开始,对后面的元素进行查找 --两数之和为 temp= - nums[0] 的元素
(1)左指针 l=1,右指针 r=nums.length-1
(2)如果 l<r,则重复下面动作
nums[l]+nums[r] 与 temp进行比较
如果大于,则右指针左移
如果小于,则左指针右移
否则,返回三元组[[i,l,r]]
3.重复以上步骤,直到i>nums.length-2

细节优化:
第二步中,判断遍历到的元素是否大于0,如果是,因为数组已经被排序过,则后面的也肯定大于0,所以没有必要继续向下比较。
第二步中,nums[l]+nums[r] ==temp后,我们直接将 i l r 存入三元组,有可能会出现重复,例如测试案例{0,0,0,0} 。两种解决方法:
(1)利用contains()判断 ans 中是否包含有我们即将存入的三元组,如果没有,则存入

if(!ans.contains(Arrays.asList(nums[i],nums[l],nums[r]))) 
{
ans.add(Arrays.asList(nums[i],nums[l],nums[r]));
}                 	   

但是由于contains()还要遍历一次List,所以时间复杂度高。
(2)我们在遍历的时候就刻意跳过重复的元素
三元组第一个元素跳过重复元素

if(i>0&&nums[i]==nums[i-1])
    				continue;

注意:这边不可以使用以下代码,测试案例{0,0,0,0,}

while(i>0&&nums[i]==nums[i-1])
  i++;

三元组后面两个元素跳过重复元素

	while (l<r && nums[l] == nums[l+1]) l++;
    while (l<r && nums[r] == nums[r-1]) r--; 

完整的代码

 public List<List<Integer>> threeSum(int[] nums) {
   	 List<List<Integer>> ans=new ArrayList<>();
    	 Arrays.sort(nums);
    	 int l,r;
    	 for (int i = 0; i < nums.length-2; i++) {	 
    		if(nums[i]<=0)
    		 {
                 if(i>0&&nums[i]==nums[i-1])
                 continue;
                 
    			l=i+1;
    			r=nums.length-1;
    			int temp=-(nums[i]);
    			while(l<r)
    			{
    				if(nums[l]+nums[r]<temp)
    					l++;
    				else if(nums[l]+nums[r]>temp)
    					r--;
    				else if(nums[l]+nums[r]==temp)
    				{
                        List<Integer> list=new ArrayList();	
    					list.add(nums[i]);
    					list.add(nums[l]);
    					list.add(nums[r]);
    					ans.add(list);
              //ans.add(Arrays.asList(nums[i],nums[l],nums[r]));
    					while (l<r && nums[l] == nums[l+1]) l++;
                        while (l<r && nums[r] == nums[r-1]) r--; 
    					l++;
                        r--;
    				}
    			}
    	
    		 }
    		else
    			break;	
	
		}
		
    	 return ans;
    }
发布了49 篇原创文章 · 获赞 2 · 访问量 894

猜你喜欢

转载自blog.csdn.net/qq_43720551/article/details/104663238
今日推荐