[leetcode日記]16.最接近的三數之和

題目

給定一個包括 n 個整數的數組 nums 和 一個目標值 target。找出 nums 中的三個整數,使得它們的和與 target
最接近。返回這三個數的和。假定每組輸入只存在唯一答案。

示例:

輸入:nums = [-1,2,1,-4], target = 1
輸出:2
解釋:與 target 最接近的和是 2 (-1 + 2 +
1 = 2) 。

提示:

3 <= nums.length <= 10^3
-10^3 <= nums[i] <= 10^3
-10^4 <= target <= 10^4

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/3sum-closest
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。

分析

本題目因爲要計算三個數,如果靠暴力枚舉的話時間複雜度會到 O(n^3),需要降低時間複雜度
首先進行數組排序,時間複雜度 O(nlogn).一般在時間複雜度大於nlgn的情況下,先排一下數組的順序往往是百利而無一害的。
在數組 nums 中,進行遍歷,每遍歷一個值利用其下標i,形成一個固定值 nums[i]
再使用前指針指向 start = i + 1 處,後指針指向 end = nums.length - 1 處,也就是結尾處
根據 sum = nums[i] + nums[start] + nums[end] 的結果,判斷 sum 與目標 target 的距離,如果更近則更新結果 ans。
同時判斷 sum 與 target 的大小關係,因爲數組有序,如果 sum > target 則 end–,如果 sum < target 則 start++,如果 sum == target 則說明距離爲 0 直接返回結果。這個其實相當於是枚舉求和中的第三個數nums3,然後計算兩數之和最接近sum-nums3。由leetcode的第一題知道,求兩數之和最接近某個數的時間複雜度是O(n)。
整個遍歷過程,固定值爲 n 次,雙指針爲 n 次,時間複雜度爲 O(n^2)
總時間複雜度:O(nlogn) + O(n^2) = O(n^2)O(nlogn)+O(n 2 )=O(n2 )

代碼

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int ans = nums[0] + nums[1] + nums[2];
        for(int i=0;i<nums.length;i++) {
            int start = i+1, end = nums.length - 1;
            while(start < end) {
                int sum = nums[start] + nums[end] + nums[i];
                if(Math.abs(target - sum) < Math.abs(target - ans))
                    ans = sum;
                if(sum > target)
                    end--;
                else if(sum < target)
                    start++;
                else
                    return ans;
            }
        }
        return ans;
    }
}


運行結果

在這裏插入圖片描述

Java的運行結果表面上看總是差強人意,讓人沒有繼續小幅度優化的動力……
如果需要優化的話,可以在i、start或者end指針移動的時候,如果遇到相同的數,可以一直移動直到不同的數爲止(也就是直接將其移動到下一個與這次枚舉到的不相同的元素)。這樣可以減少重複計算相同的數求和的次數。
另外一方面,在上面代碼中已經實現的一個小優化就是當計算得到某三個數求和結果已經等於sum的時候,可以直接返回結果,因爲這肯定是最接近sum的結果了。

代碼2

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int ans = nums[0] + nums[1] + nums[2];
        for(int i=0;i<nums.length;i++) {
            int start = i+1, end = nums.length - 1;
            while(start < end) {
                int sum = nums[start] + nums[end] + nums[i];
                if(Math.abs(target - sum) < Math.abs(target - ans)) {
					ans = sum;
				} 
                if(sum > target)
                    do ( end-- ) while (nums[end] == nums[end+1]);
                else if(sum < target)
                     do ( start++ ) while (nums[start] == nums[start-1]);
                else	
                    return ans;
            }
        }
        return ans;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章