LeetCode[15、16] - 三个数之和&&最接近的三个数之和


正文

这种题目没有什么复杂的算法逻辑,也用不到动态规划,考察的就是一个思维能力,能想明白,就能写的出来。当然,最后落实在代码上还需要考略多种情况,逻辑严谨。

题目一:三个数之和

【源于LeetCode - 15】(中等)

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。

示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

示例 2:
输入:nums = []
输出:[]

示例 3:
输入:nums = [0]
输出:[]

我的思路:

我的老师曾说过:“没有两个for循环解决不了的问题,如果有,就再加一个”。小编采用的是偏向暴力解法,冒泡排序的理念。事后看了看其他人的方案,对比下来,还是我写的这种更容易理解,时间和内存消耗中上水平,还不错。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        // 先排序,方便计算
        Arrays.sort(nums);
        // 把题干中的0当成变量设置,让代码更灵活
        int sum = 0;
        for (int i = 0;i < nums.length;i++) {
            // 排序之后如果第一个元素已经大于 sum,那么无论如何组合都不可能凑成三元组
            // 直接返回结果就可以了
            if (nums[i] > sum)  break;

            // 错误去重方法,将会漏掉-1,-1,2 这种情况
            // if (nums[i] == nums[i + 1]) continue;

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

            int left = i + 1, right = nums.length - 1;
            while (right > left) {
                int temp = nums[i] + nums[left] + nums[right];
                if (temp == sum) {
                    result.add(Arrays.asList(nums[i], nums[left], nums[right]));

                    // 去重用的
                    while (right > left && nums[left] == nums[left+1]) left++;
                    while (right > left && nums[right] == nums[right-1]) right--;

                    // 找到答案时,双指针同时收缩
                    left++;
                    right--;
                } else if (temp > sum) {
                    right--;
                } else {
                    left++;
                }
            }
        }
        return result;
    }
}

题目二:最接近的三个数之和

【源于LeetCode - 16】(中等)

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数,使它们的和与 target 最接近。返回这三个数的和。注意:假定每组输入只存在恰好一个解。

示例 1:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

示例 2:
输入:nums = [0,0,0], target = 1
输出:0
 
提示:
3 <= nums.length <= 1000
-1000 <= nums[i] <= 1000
-104 <= target <= 104

我的思路:

这是 LeetCode - 15 题目的变形,思路是一样的,但是题目里没有将一定等于目标值,最接近的思路就是使用绝对值 Math.abs(),确保结果最接近。

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        // 先排序
        Arrays.sort(nums);
        int min = nums[0] + nums[1] + nums[2];
        for (int i = 0;i < nums.length;i++) {
            // 设置左右指针
            int left = i+1, right = nums.length-1;
            while (right > left) {
                int threeSum = nums[i] + nums[left] + nums[right];
                // 计算最小绝对值的min
                if (Math.abs(threeSum - target) < Math.abs(min - target)) {
                    min = threeSum;
                }
                if (threeSum > target) {
                    right--;
                } else if (threeSum < target) {
                    left++;
                } else {
                    // 如果已经等于 target 的话, 肯定是最接近的
                    return threeSum;
                }
            }
        }
        // 通知GC,本行代码影响不大
        System.gc();
        return min;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_44259720/article/details/123200449