三数之和
问题描述:
给你一个包含 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);
}
}
解法一提交结果:
解法二提交结果: