34. 在排序数组中查找元素的第一个和最后一个位置 + 二分查找

题目来源

LeetCode_34

题目描述

题解分析

解法一:二分法

  1. 这里与传统的二分法不同,这里需要找到指定元素的左右边界,所以我们无法直接套用二分法的模板。
  2. 其实,我们可以分别考虑这两种情况,与普通的二分法不同,当需要找左边界时,当我们找到target == nums[mid],我们不是直接返回,而是继续向左找:high = mid - 1;同理,找右边界时,我们继续向右找:low = mid + 1。
class Solution {
    public int[] searchRange(int[] nums, int target) {
        return new int[]{searchLeft(nums, target), searchRight(nums, target)};
    }
    private int searchLeft(int[] nums, int target){
        int n = nums.length;
        int left = 0, right = n-1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                right = mid - 1;
            }else if(nums[mid] < target){
                left = mid + 1;
            }else if(nums[mid] > target){
                right = mid -1;
            }
        }
        if(left >= 0 && left < n && nums[left] == target){
            return left;
        }
        return -1;
    }
    private int searchRight(int[] nums, int target){
        int n = nums.length;
        int left = 0, right = n-1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] == target){
                left = mid + 1;// 与普通的二分搜索不同,这里不是直接返回,而是继续向左查找
            }else if(nums[mid] < target){
                left = mid + 1;
            }else if(nums[mid] > target){
                right = mid -1;
            }
        }
        if(right >= 0 && right < n && nums[right] == target){
            return right;
        }
        return -1;
    }
}

解法二:二分法优化

  1. 考虑到上面的二分法相对比较复杂,它需要定义两个方法,其实这两种情况可以一起考虑。
  2. 我们可以设置一个变量来保存结果,只不过这个返回的结果需要再额外处理一下,即需要针对左右边界进行修改。
class Solution {
    public int[] searchRange(int[] nums, int target) {
        if(nums == null || nums.length == 0)
            return new int[]{-1, -1};
        
        int low = binarySearch(nums, target, false)  + 1;// 左边界需要+1
        int high = binarySearch(nums, target, true);// 右边界
        if(low <= high && high != -1 && nums[low] == target && nums[high] == target)
            return new int[]{low, high};
        else return new int[]{-1, -1};
    }

    public int binarySearch(int[] nums, int target, boolean flag){
        int ans = -1;
        int low = 0, high = nums.length - 1;
        while(low <= high){//这里是小于等于,因为可能一开始数组只有一个元素
            int mid = (low + high) / 2;
            if((flag && nums[mid] <= target) || nums[mid] < target){
                low = mid + 1;
                ans = mid;//这步很关键,记录答案的位置
            }else{
                high = mid - 1;
            }
        }
        return ans;
    }
}
posted @ 2021-03-28 22:20  Garrett_Wale  阅读(58)  评论(0编辑  收藏  举报