LeetCode [15、16]-3つの数値の合計&&最も近い3つの数値の合計


文章

この種のトピックには複雑なアルゴリズム論理はなく、動的計画法は使用されません。テストされるのは思考能力です。理解できれば、それを書くことができます。もちろん、コードの最終的な実装では、考慮する必要のある多くの状況があり、ロジックは厳密です。

トピック1:3つの数値の合計

[LeetCode-15から](中程度)

n個の整数を含む配列numsが与えられた場合、a + b + c = 0となるようなnumsに3つの要素a、b、cがあるかどうかを判断しますか?合計が0で、繰り返されないすべてのトリプルを見つけてください。注:回答に重複するトリプルを含めることはできません。

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

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

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

私の思考の列:

私の先生はかつて、「2つのforループが解決できないという問題はありません。もしあれば、もう1つ追加してください」と言いました。編集者は、ブルートフォースソリューションとバブルソートの概念を採用しています。他の人の計画を見てみると、自分が書いたものの方がわかりやすく、時間もメモリ消費量も中〜高レベルで悪くないことがわかりました。

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;
    }
}

トピック2:最も近い3つの数値の合計

[LeetCode-16から](中程度)

長さnの整数配列numsとターゲット値targetが与えられます。合計がターゲットに最も近いnumsから3つの整数を選択してください。これらの3つの数値の合計を返します。注:入力のセットごとに1つのソリューションが存在すると想定されています。

示例 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