leetcode刷题:哈希表07 (三数之和)

93 篇文章 0 订阅

第15题. 三数之和

力扣题目链接

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。

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

示例:

给定数组 nums = [-1, 0, 1, 2, -1, -4],

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

这题。。。放弃了,看题解吧。九成五的测例通过,说明思路是正确的,只是超时。没办法,测例太长了。

package com.programmercarl.hashtable;

import java.util.*;

/**
 * @ClassName sum3
 * @Descriotion TODO
 * @Author nitaotao
 * @Date 2022/6/21 15:03
 * @Version 1.0
 **/
public class sum3 {
  
    public static List<List<Integer>> threeSum(int[] nums) {
        /**
         * 依旧可以使用hashmap,
         * 三数之和,其实当前两个数确定时,最后一个数已经确定了。
         * 可以把前两数获取到,再计算最后一个数,为防止一样,三数排序作为键
         */
        List<List<Integer>> result = new ArrayList<>();
        int temp;
        HashMap<String, String> map = new HashMap<>();
        for (int i = 0; i < nums.length - 2; i++) {
            for (int j = i + 1; j < nums.length - 1; j++) {
                //第三个数
//                temp = 0 - nums[i] - nums[j];
                temp = -(nums[i] + nums[j]);
                //三数排序,降序
                String key = order3(nums[i], nums[j], temp);
                map.put(key, i + "#" + j + "=" + temp);
            }
        }
        //只有出现过的才算正确
        Set<String> set = new HashSet<>();
        Set<String> keys = map.keySet();
        for (String key : keys) {
            for (int i = 0; i < nums.length; i++) {
                //值
                String valStr = map.get(key);
                //当前被比较的值,不一定存在
                int value = Integer.parseInt(valStr.split("=")[1]);
                if (value == nums[i]) {
                    //再判断这个数是不是自己
                    //如果不是,再添加
                    //位置进行比较
                    //位置
                    String[] pos = valStr.split("=")[0].split("#");
                    if (!(pos[0].equals(String.valueOf(i)) || pos[1].equals(String.valueOf(i)))) {
                        set.add(key);
                    }
                }
            }
        }
        //处理结果集,去重
        for (String res : set) {
            List<Integer> resultList = new ArrayList<>();
            String[] split = res.split("#");
            resultList.add(Integer.valueOf(split[0]));
            resultList.add(Integer.valueOf(split[1]));
            resultList.add(Integer.valueOf(split[2]));
            result.add(resultList);
        }
        return result;
    }

    /**
     * 三数降序排序
     *
     * @param nums1
     * @param nums2
     * @param nums3
     * @return
     */
    public static String order3(int nums1, int nums2, int nums3) {
        if (nums1 > nums2) {
            if (nums1 > nums3) {
                //nums1最大
                if (nums2 > nums3) {
                    return "" + nums1 + "#" + nums2 + "#" + nums3;
                } else {
                    return "" + nums1 + "#" + nums3 + "#" + nums2;
                }
            } else {
                //nums1没nums3大
                return "" + nums3 + "#" + nums1 + "#" + nums2;
            }
        } else {
            //nums2>nums1
            if (nums2 > nums3) {
                if (nums1 > nums3) {
                    return "" + nums2 + "#" + nums1 + "#" + nums3;
                } else {
                    return "" + nums2 + "#" + nums3 + "#" + nums1;
                }
            } else {
                //nums1最大
                return "" + nums3 + "#" + nums2 + "#" + nums1;
            }
        }
    }
}

在这里插入图片描述

我的思路是用hashmap做
三数之和,其实当前两个数确定时,最后一个数已经确定了。
可以把前两数获取到,再计算最后一个数,为防止一样,三数排序作为键
为了防止键重复,先把元素排序,再存在键中,值的构成是 第一个元素的位置#第二个元素的位置=需要的元素的值。
符号只是标记为。
因为两个值确定了,第三个值就已经确定了,先不管有没有,先存起来。
再遍历一遍,看看第三个值在不在,如果存在,且位置不是前两个元素的值,则成功找到这个序列。

==============================================================================
hhhhh
在看题解,就差念我身份证号了。
在这里插入图片描述
真就一个力扣搞一天了。
1:如果数组长度<3直接返回。
2:数组排序,升序。
3:从第一位开始为基准,建立右边第一个元素为左指针,最后一个元素为右指针。
4:如果第一个元素>0,即最小的元素>0,直接返回吧,不用看了。
5:如果除了第一个元素,之后的基准元素和前一个一样,则跳过,因为结果重复了。
6:以基准元素为第一个和数,之后的第二个和第三个和数,分别来自左指针和右指针。
7:左右指针变换规律和基准元素相似,和自己的上个元素不得重复,不然就结果重复了。
8:直到左、右都和自己的上一个不同时,根据sum的值进位,值>0,则右边减一点,值<0,则左边加一点,毕竟是升序的。直到左右重合,结束循环。
9:基准元素不断后移。

    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        //数组的长度
        int len = nums.length;
        //当数组的长度小于3时,直接退出
        if (len < 3) {
            return result;
        }
        //将数组排序,升序
        Arrays.sort(nums);
        for (int i = 0; i < len; i++) {
            //如果遍历的起始元素大于0,则直接退出
            //因为是升序的,说明最小值都大于0,直接结束
            if (nums[i] > 0) {
                break;
            }
            //去重,当起始的值等于前一个元素,那么得到的结果将会与前一次相同。
            /**
             * 诸如 -1 -1 2
             * 只用计算第一个-1的,会把第二个-1计入
             * 再以第二个-1计算时,在多代入第一个就重复了。
             */
            if (i > 0 && nums[i] == nums[i - 1]) {
                continue;
            }
            //左指针
            int left = i + 1;
            //右指针
            int right = len - 1;
            //当左不等于右时
            while (left < right) {
                //三数相加
                int sum = nums[i] + nums[left] + nums[right];
                //如果等于0,则加入结果集
                if (sum == 0) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                    //将左右指针移动时,先对左右指针的值进行判断,重复则跳过
                    while (left < right && nums[left] == nums[left + 1]) {
                        left++;
                    }
                    //去重,因为 i不变,当此时 r 取的数的值与前一个相同,所以不用在计算
                    while (left < right && nums[right] == nums[right - 1]) {
                        right--;
                    }
                    //当左边和右边都不在和前一个相同时
                    left++;
                    right--;
                } else if (sum < 0) {
                    left++;
                } else if (sum > 0) {
                    right--;
                }
            }
        }
        return result;
    }

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值