天天看点

[leetcode] 34. Find First and Last Position of Element in Sorted Array

Given an array of integers 

nums

 sorted in ascending order, find the starting and ending position of a given 

target

 value.

Your algorithm's runtime complexity must be in the order of O(log n).

If the target is not found in the array, return 

[-1, -1]

.

Example 1:

Input: nums = [         5,7,7,8,8,10]                , target = 8
Output: [3,4]      

Example 2:

Input: nums = [         5,7,7,8,8,10]                , target = 6
Output: [-1,-1]      

这个题目嘛,大部分人肯定和我一样,第一反应绝对是暴力

确实暴力的话这题秒解,时间复杂度也只会是O(n)而已

然而题目要求了O(log n)那肯定要其他做法

很明显O(log n)的话只有二分查找了

一开始我想用递归做的,因为快排也是递归的嘛,后面想了想最后结果是返回2个值,递归的话好像不好搞啊

于是还是循环去搞了

我犯了一个错误,导致我迟迟没解出来

首先肯定知道要分3类,我就分了三类,小于target、大于target和刚好等于target的情况

我错就错在等于target的时候,处理不对,我一开始是以为刚好等于target的时候,只有这个数和相邻的一个数的坐标能返回

后面错了N次后才发现不对

于是就针对刚好等于target一定要有一个解决方法

前面错得太多次了,经过反思,就是我题目意思理解错了

如果是找间隔最远的2个坐标,那向两端找就行了啊!

想通了之后,于是我就很快解出来了

具体方法如下

首先定义一个middle = (left + right) / 2

这个不解释了

从中间开始,如果nums[middle] > target,那么很明显target在middle的左边,所以这时候right = middle - 1;

如果nums[middle] < target,那么left = middle + 1;

最重要的就是如果nums[middle] == target

那么,我们就把left、right都放到middle,也就是left = middle,right = middle;

然后就是从中间往两边搜索了

保证数组不要越界即可

总结来说本题就是先用二分查找法从中间去分治,压缩搜索空间

找到结果后又重新从中间往两边搜索,返回结果

java代码如下:

public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        
        int []answer = new int[]{-1,-1};
        
        if(nums.length == 0)
            return answer;
        
        if(nums[0] > target || nums[nums.length - 1] < target)
            return answer;
        
        while(left <= right){
            int middle = (left + right) / 2;
            if(nums[middle] < target){
                left = middle + 1;
            }
            
            if(nums[middle] > target){
                right = middle - 1;
            }
            
            //找到了之后,从中间向两边找到坐标
            if(nums[middle] == target){
                left = middle;
                right = middle;
                
                while(left != 0 && nums[left - 1] == target){
                    left--;
                }
                
                while(right != nums.length - 1 && nums[right + 1] == target){
                    right++;
                }
                
                answer[0] = left;
                answer[1] = right;
                break;
            }
        }
        return answer;
    }
           

我也没想到用时会这么短

不过貌似内存耗得很大?