代码重构: leetcode 16. 最接近的三数之和

137 阅读1分钟

16. 最接近的三数之和

题目和第十五题是类似的,解题方式也是一样:先排序,固定一个最小数字,然后再按照寻找target的方式来。

但这题的难点在于,如何证明或者说理解解答方式的正确性。

下面做一个简略的证明:

在我们的每一步固定一个数字后,假设为x,之后的寻找target-x的过程必然覆盖了最小的绝对值,设此时数组为num,左指针为left,右指针为right。

假设我们当前的一次操作是left++,也就意味着当前的情况是num[left]+num[right]<target。

采用反证法,假设因为此时left++操作导致得不到正确答案,又因为我们始终能按正确的寻找有序数组里面的两数和的方式迫近target。

就意味着,最终答案是由当前num[left]参与组成,,那么此时操作right--,但是显然此时num[left]+num[right]<target,num[left]+num[right-1]<=num[left]+num[right]<target,若num[right-1]==num[right],显然又回到了之前状态,所以我们总是假设为以下状态:

num[left]+num[right1]<num[left]+num[right]<targetnum[left]+num[right-1]<num[left]+num[right]<target

于是,如果此时进行right移动,首先不满足[在有序数组里面寻找target]的操作,其次和只会越来越远离target,所以必然能找找答案。

 public int threeSumClosest(int[] nums, int target) {
        int ans = nums[0]+nums[1]+nums[2];
        Arrays.sort(nums);
        for (int i = 0; i <= nums.length - 3; i++) {
            int left = i + 1, right = nums.length - 1;
            while (left < right ) {
                int temp = nums[left] + nums[right]+nums[i];
                if (Math.abs(ans- target) > Math.abs(temp- target)) {
                    ans = temp;
                }
                if (temp < target) {
                    left++;
                } else if (temp > target) {
                    right--;
                } else return target;
            }
        }
        return ans;
    }