leetcode34 search for a range

題目要求

Given an array of integers 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].

For example,
Given [5, 7, 7, 8, 8, 10] and target value 8,
return [3, 4].

即 在一個有序排列的數組中,找到目標值所在的起始下標和結束下標。若是該目標值不在數組中,則返回[-1,-1]
題目中有一個特殊要求是時間複雜度爲O(logn),也就是在暗示咱們,不能只是單純的按照順序遍歷數組,要儘可能減去無效遍歷。因此這題的核心思路爲二分法遍歷。面試

思路一 二分法初級運用

最初的思路是使用二分法找到目標值的其中一個下標,再根據該下標左右遍歷得出初始下標和結束下標。數組

public int[] searchRange(int[] nums, int target) {
        int[] result = new int[]{-1, -1};
        int left = 0;
        int right = nums.length-1;
        while(left<=right){
            int mid = (left + right)/2;
            if(nums[mid]==target){
                while(mid>=left && nums[mid]==target){
                    mid--;
                }
                result[0] = mid+1;
                mid = (left + right)/2;
                while(mid<=right && nums[mid]==target){
                    mid++;
                }
                result[1] = mid - 1;
                break;
            }else if (nums[mid] > target){
                right = mid-1;
            }else{
                left = mid+1;
            }
        }
        return result;
    }

思路二:二分法分別運用

假設咱們目前有左指針,右指針,並判斷中間值和目標值之間的關係,那麼一共有三種關係狀況微信

  1. 中間值小於目標值,則目標值只可能在右子數組
  2. 中間值大於目標值,則目標值只可能在左子數組
  3. 中間值等於目標值,則目標值在左右子數組均可能存在

結合狀況1和狀況3,當中間值小於目標值,則將左指針右移至中間,不然將右指針左移至中間。這樣必定能夠找到目標值的初始下標
同理,結合狀況2和狀況3,當中間值大於目標值,則將右指針左移至中間,不然將左指針右移至中間,這樣必定能夠找到目標值的結束下標。spa

public int[] searchRange2(int[] nums, int target) {
        int[] range = new int[]{nums.length, -1};
        searchRange2(nums, target, 0, nums.length, range);
        if(range[0]>range[1]) range[0]=-1;
        return range;
    }
    public void searchRange2(int[] nums, int target, int left, int right, int[] range){
        if(left>right) return;
        int mid = ( left + right ) / 2;
        if(nums[mid] == target){
            if(mid < range[0]){
                range[0] = mid;
                searchRange2(nums, target,left, mid-1, range);
            }
            if(mid > range[1]){
                range[1] = mid;
                searchRange2(nums, target, mid+1, right, range);
            }
        }else if (nums[mid]<target){
            searchRange2(nums, target, mid+1, right, range);
        }else{
            searchRange2(nums, target, left, mid-1, range);
        }
    }

這種思路更清晰的代碼表示以下指針

public int[] searchRange3(int[] nums, int target) {
        int[] result = new int[2];
        result[0] = findFirst(nums, target);
        result[1] = findLast(nums, target);
        return result;
    }

    private int findFirst(int[] nums, int target){
        int idx = -1;
        int start = 0;
        int end = nums.length - 1;
        while(start <= end){
            int mid = (start + end) / 2;
            if(nums[mid] >= target){
                end = mid - 1;
            }else{
                start = mid + 1;
            }
            if(nums[mid] == target) idx = mid;
        }
        return idx;
    }

    private int findLast(int[] nums, int target){
        int idx = -1;
        int start = 0;
        int end = nums.length - 1;
        while(start <= end){
            int mid = (start + end) / 2;
            if(nums[mid] <= target){
                start = mid + 1;
            }else{
                end = mid - 1;
            }
            if(nums[mid] == target) idx = mid;
        }
        return idx;
    }

clipboard.png
想要了解更多開發技術,面試教程以及互聯網公司內推,歡迎關注個人微信公衆號!將會不按期的發放福利哦~code

相關文章
相關標籤/搜索