21-算法打卡-哈希表-三数之和-leetcode(15)-第二十一天

1 题目地址

15. 三数之和 - 力扣(LeetCode)15. 三数之和 - 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。  示例 1:输入:nums = [-1,0,1,2,-1,-4]输出:[[-1,-1,2],[-1,0,1]]解释:nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。注意,输出的顺序和三元组的顺序并不重要。示例 2:输入:nums = [0,1,1]输出:[]解释:唯一可能的三元组和不为 0 。示例 3:输入:nums = [0,0,0]输出:[[0,0,0]]解释:唯一可能的三元组和为 0 。 提示: * 3 <= nums.length <= 3000 * -105 <= nums[i] <= 105https://leetcode.cn/problems/3sum/description/


2 题目说明

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != ji != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。

示例 1:

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。

示例 2:

输入:nums = [0,1,1]
输出:[]
解释:唯一可能的三元组和不为 0 。

示例 3:

输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。

提示:

  • 3 <= nums.length <= 3000
  • -105 <= nums[i] <= 105

3 解题思路

方式一:暴力破解法:三层循环,判断nums[i]+nums[j]+nums[k]=0,则记录下来;去重:将nums[i]+nums[j]+nums[k]=0的三个数据排序后生成都逗号分隔的字符串放到set集合中,重复则不记录到返回结果中,不重复则记录。

方式二:双指针法
1、首先给原数组排序,从小到大 (可以根据相加大于 小于 等于0结果判断如何移动)
2、定义初始指针i(索引为0), left(指针i+1位置), right(指针nums.length-1位置)
3、判断三个值相加的结果,决定如何移动
3.1、nums[i]>0:结束,最小值都小于0,所以不会存在三者相加等于0
3.2、nums[i]+nums[left]+nums[right]>0:right--,使三者相加的值变小
3.3、nums[i]+nums[left]+nums[right]<0:left++,使三者相加的值变大
3.4、nums[i]+nums[left]+nums[right]=0:记录结果集合,left++,right-- 保证left<right
4、去重,答案中不能包含相同的三元素,三个指针都要考虑去重( i left  right)
4.1、nums[i]=nums[i+1],不能这样去重不能有重复的三元组,但三元组内的元素是可以重复的
4.2、nums[i]=nums[i-1],此时需要去重,因为nums[i]已经将与nums[left]、nums[right]相加等于0结果记录下来了
4.3、同理left、right相同的操作;
        nums[left]=nums[left-1], 则left++
        nums[right]=nums[right+1], 则right--;right只从最右侧,向左移动的,所以去重方向跟left是
               相反的


4 代码编写


4.1 暴力方式

三层循环,报超时

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> resultList = new ArrayList<>();
        Set<String> hashSet = new HashSet<>();
        for (int i=0; i<nums.length-2; i++) {
            for (int j=i+1; j<nums.length-1; j++) {
                for (int k = j + 1; k < nums.length; k++) {
                    if (nums[i] + nums[j] + nums[k] == 0) {
                        List<Integer> itemList = Arrays.asList(nums[i], nums[j], nums[k]);
                       Collections.sort(itemList);
                        String join = toStr(itemList);
                        if (!hashSet.contains(join)) {
                            hashSet.add(join);
                            resultList.add(itemList);
                        }
                    }
                }
            }
        }
        return resultList;
   } 

   public String toStr(List<Integer> itemList) {
        String a = "";
        for (int i=0; i<itemList.size(); i++) {
            a += itemList.get(i) + "-";
        }
        return a;
    }
}


4.2 双指针法

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
       Arrays.sort(nums);
       List<List<Integer>> resultList = new ArrayList<>();
        for (int i=0; i<nums.length; i++) {
            // 最小值大于0,则不会存在三数之和等于0的情况
            if (nums[i]>0) {
                return resultList;
            }
            // 去重逻辑,继续向右移动
            if (i>=1 && nums[i]==nums[i-1]) {
                continue;
            }
            int left = i + 1;
            int right = nums.length - 1;
            while (left<right) {
                int result = nums[i] + nums[left] + nums[right];
                if (result==0) {
                    List<Integer> itemList = new ArrayList<>();
                    itemList.add(nums[i]);
                    itemList.add(nums[left]);
                    itemList.add(nums[right]);
                    resultList.add(itemList);

                    // 去重逻辑,对b 和 c去重
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;

                    left++;
                    right--;
                } else if (result>0) {
                    right--;
                } else {
                    left++;
                }
            }
        }
       return resultList;
   } 
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值