LeetCode 第15、18题 三数之和 四数之和



三数之和

问题描述:

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



解题思路:

解法一:双指针移动,HashSet去重
  确定了一个数,剩下两个数的和就可以确定了,即第一个数的相反数(target)。先将数组进行排序,方便后面的双指针移动;两个指针分别指向头尾,当两个数的和大于target,则将右边的指针向左移一格,当两个数的和小于target,则将左边的指针向右一格。如果相等则添加到set中,并且两个指针都向中间移一格。

解法二:双指针移动,手动去重
  和解法一主体相同,只是不用HashSet去重,少去了转换的时间;可以提高效率。



代码实现:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

public class text15三数之和 {
	  
	  //HashSet去重
	  public List<List<Integer>> threeSum1(int[] nums) {
		  	Arrays.sort(nums);
	    	HashSet<List<Integer>> set = new HashSet<List<Integer>>();
	    	for(int i=0; i<nums.length-2; i++) {
	    		int target = -nums[i];
	    		int j = i+1;
	    		int k = nums.length-1;
	    		while(j<k) {
	    			if(nums[j]+nums[k]==target) {
	    				List<Integer> temp = new ArrayList<Integer>();
	    				temp.add(nums[i]);
	    				temp.add(nums[j]);
	    				temp.add(nums[k]);
	    				set.add(temp);
	    				j++;  k--;
	    			}else if(nums[j]+nums[k]>target){
	    				k--;
	    			}else {
	    				j++;
	    			}
	    		}
	    	}
	    	List<List<Integer>> list = new ArrayList<List<Integer>>(set);
	    	return list;
	    }
	
	  
	  //手动去重
	  public List<List<Integer>> threeSum(int[] nums) {
		  	Arrays.sort(nums);
	    	//HashSet<List<Integer>> set = new HashSet<List<Integer>>();
	    	List<List<Integer>> list = new ArrayList<List<Integer>>();
	    	for(int i=0; i<nums.length-2; i++) {
	    		if(i>0) {
	    			while(i<nums.length-2 && nums[i]==nums[i-1]) {
	    				i++;
	    			}
	    		}
	    		int target = -nums[i];
	    		int j = i+1;
	    		int k = nums.length-1;
	    		while(j<k) {
	    			if(nums[j]+nums[k]==target) {
	    				List<Integer> temp = new ArrayList<Integer>();
	    				temp.add(nums[i]);
	    				temp.add(nums[j]);
	    				temp.add(nums[k]);
	    				list.add(temp);
	    				j++;  k--;
	    				while(j<nums.length && k>0 && nums[j]==nums[j-1] && nums[k]==nums[k+1]) {
	    					j++;  k--;
	    				}
	    			}else if(nums[j]+nums[k]>target) {
	    				k--;
	    				while(k>0 && nums[k]==nums[k+1]) {  //跳过重复的数字
	    					k--;
	    				}
	    			}else {
	    				j++;
	    				while(j<nums.length && nums[j]==nums[j-1]) {  
	    					j++;
	    				}
	    			}
	    		}
	    	}
	    	return list;
	    }
}

解法一提交结果:
在这里插入图片描述

解法二提交结果:
在这里插入图片描述



四数之和

问题描述:

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a +
b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。

注意:

答案中不可以包含重复的四元组。

示例:

给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。

满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/4sum



解题思路:

解法一:暴力破解,四层循环,使用HasheSet去重

解法二:双指针移动,HashSet去重
   使用四个指针(a<b<c<d)。固定最小的a和b在左边,c=b+1,d=size-1 移动两个指针包夹求解。保存使得nums[a]+nums[b]+nums[c]+nums[d]==target的解。偏大时d左移,偏小时c右移。c和d相遇时,表示以当前的a和b为最小值的解已经全部求得。b++,进入下一轮循环b循环,当b循环结束后。 a++,进入下一轮a循环。



代码实现:


import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;

public class text18四数之和 {
	
	public static void main(String[] args) {
		int[] nums = {1,0,-1,0,-2,2};
		System.out.println(fourSum2(nums, 0));
	}
	
	//暴力破解,四层循环
    public List<List<Integer>> fourSum(int[] nums, int target) {
    	Arrays.sort(nums);
    	HashSet<List<Integer>> set = new HashSet<List<Integer>>();
    	for(int i=0; i<nums.length-3; i++) {
    		for(int j=i+1; j<nums.length-2; j++) {
    			for(int k=j+1; k<nums.length-1; k++) {
    				for(int l=k+1; l<nums.length; l++) {
    					if(nums[i]+nums[j]+nums[k]+nums[l]==target) {
    						List<Integer> temp = new ArrayList<Integer>();
    						temp.add(nums[i]);
    						temp.add(nums[j]);
    						temp.add(nums[k]);
    						temp.add(nums[l]);
    						set.add(temp);
    					}
    				}
    			}
    		}
    	}
    	return new ArrayList<List<Integer>>(set);
    }
    
    //双指针移动
    public static List<List<Integer>> fourSum2(int[] nums, int target) {
    	Arrays.sort(nums);
    	HashSet<List<Integer>> set = new HashSet<List<Integer>>();
    	int a = 0;
    	int b = a+1;
    	int c = b+1;
    	int d = nums.length-1;
    	for(; a<nums.length-3; a++) {
    		for(b=a+1; b<nums.length-2; b++) {
    			c = b+1;
    			d = nums.length-1;
    			while(c<d) {
					int sum = nums[a]+nums[b]+nums[c]+nums[d];
					if(sum<target) {
						c++;
						while(c<d && nums[c]==nums[c-1])
							c++;
					}else if(sum>target) {
						d--;
						while(d>c && nums[d]==nums[d+1])
							d--;
					}else {
						List<Integer> temp = new ArrayList<Integer>();
						temp.add(nums[a]);
						temp.add(nums[b]);
						temp.add(nums[c]);
						temp.add(nums[d]);
						set.add(temp);
						c++; d--;
					}
    			}
    		}
    	}
    	return new ArrayList<List<Integer>>(set);
    }
}

解法一提交结果:
在这里插入图片描述

解法二提交结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥自在”

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值