力扣题--最接近的它

253 阅读3分钟

题目

屏幕截图 2023-11-15 195031.png

首先看到题目是不是想到就不过是求最接近的麻 ,简单,直接几个循环套上去得了

这样可以但是时间复杂度怎么办o(n^3)应该是有的.

思路

首先我们应该想到双指针的方法.诶?双指针怎么处理三个量呢?

双指针是不是都是从一个数组的start和end开始的吗??

那么只要我们实现每次遍历变它们后改变start和endde 初始值就行了

对于代码,我们第一件要做的事是对数组进行由大到小的排序 可以用sort的方法快速完成,这是为了双指针移动时的条件为前后两次绝对值大小比较的结果

再用math.abs去求绝对值,在比较前后两次绝对值的大小就行了

代码实现

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

那么这就是一个简单的双指针代码了可以看到

屏幕截图 2023-11-15 201018.png 这里仅仅只超过了20%的用户,那剩下的80%的人是怎么做到的呢/?

代码优化

1.元素重复的问题 举个例子,nums = [1,1,1,2,3] target = 7,那么最终的结果应该是 6 (1 + 2 + 3)。

但是按照上面的代码,在遍历的时候 nums[i]会重复的等于 1 这个数,但是其实之前 nums[i] 等于 1 已经遍历过了,后面的遍历都属于无用的遍历。

所以可以添加去重的操作

2.超越界限的问题 举个例子,nums = [-3,-1,3,4,5]。 假设 i = 0,left = 1,right = 4,那么每次 left 和 right 之间都有许多元素,那么 left 和 right 之间的元素之和肯定也有一个最小值和一个最大值。

就如同 left = 1,right = 4,那么移动指针的情况下,nums[left] + nums[right] 的最小值肯定为 nums[left] + nums[left + 1],因为这两个元素是 left 和 right 范围内能取到的最小的两个元素,同理可证最大值。

如果 target 的值比 nums[i] + nums[left] + nums[left + 1] 的值还小,那么双指针无论怎么取,最后都会取到 nums[i] + nums[left] + nums[left + 1]。 同理可证 target 的值比nums[i] + nums[right] + nums[right - 1] 的值还大的情况。 所以可以增加一个判断,满足条件的情况下就可以直接取值,而不需要双指针一步步的判断来进行取值,减少了双指针的移动。

3.三数之和等于 target 的问题 举个例子,nums = [1,1,2,3,4,5,6,10] target = 12,那么最终的结果应该是 12 (1 + 1 + 10)。 有些时候,可能会直接找到三数之和等于 target 的情况,此时直接返回结果即可,不需要在进行之后的循环,因为不可能有数比他自己更接近自己了。

4.完整代码

public int threeSumClosest(int[] nums, int target) {
        Arrays.sort(nums);
        int result = nums[0] + nums[1] + nums[2];
        for(int i=0;i<nums.length-2;i++){
            int left = i+1;
            int right = nums.length - 1;
            while(left != right){
                int min = nums[i] + nums[left] + nums[left + 1];
                if(target < min){
                    if(Math.abs(result - target) > Math.abs(min - target))
                        result = min;
                    break;
                }
                int max = nums[i] + nums[right] + nums[right - 1];
                if(target > max){
                    if(Math.abs(result - target) > Math.abs(max - target))
                        result = max;
                    break;  
                }
                int sum = nums[i] + nums[left] + nums[right];
                // 判断三数之和是否等于target
                if(sum == target)
                    return sum;
                if(Math.abs(sum - target) < Math.abs(result - target))
                    result = sum;
                if(sum > target){
                    right--;
                    while(left != right && nums[right] == nums[right+1])
                        right--;
                }
                else{
                    left++;
                    while(left != right && nums[left] == nums[left-1])
                        left++;
                }
            }
            while(i<nums.length-2 && nums[i] == nums[i+1])
                i++;
        }
        return result;
    }


这样处理完那么就超过99.9%的用户了

小编也是看大神的文章才成为那个0.1%