0
点赞
收藏
分享

微信扫一扫

Web3 知识体系架构图

冶炼厂小练 2024-05-26 阅读 30

题目链接 

题目:

分析: 

  • 如果我们查找元素的第一个位置, 随便假设一个位置为x,
    • 如果这个数>target, 说明 [left,x-1] 是我们要找的位置, [x,right] 可以舍去, 让right =mid-1,
    • 如果这个数==target, 说明[left,x] 是我们要找的位置, [x+1,right] 可以舍去, 让right = mid,
    • (因为当这个数>= target时, 我们都移动right, 所以可以合并, 但是right只能=mid)
    • 如果这个数<target, 说明[left,x] 可以舍去, [x+1,right] 是我们要找的位置, 让left = mid+1
  • 此时说明, 数组具有"二段性", 说明可以使用"二分查找"
  • 但是如果是用第一种二分查找: 朴素的二分查找, 发现我们不能确定当nums[mid] == target时, 它一定是我们要找的第一个位置或最后一个位置
  • 细节:
    • 1. 判断循环的条件, 一定是left < right , 不能写=
      • 原因1: 因为我们要找元素的第一个位置, 如果当left == right 时, 说明此时的位置, 一定最终的结果, 无需再移动left和right
      • 原因2: 如果当left == right 时, mid也==right == left, 如果进入循环, 那么如果此时这个数就是target, right = mid, 那么right的位置并没有变化, 此时还满足left<=right的条件, 就会形成死循环!!
    • 2. 求中点的操作, 一定是 int mid = left + (right - left)/2
      • 我们知道求中点我们有两种选择, 一种是 int mid = left + (right-left)/2 , 一种是 int mid = left + (right-left+1)/2, 这两种方式唯一的区别是当数组的大小为偶数时, /2之后是向下取整还是向上取整
      • 那么此时, 如果我们选择向上取整, 即int mid = left + (right-left+1)/2, 那么当下面这种情况出现时, 此时mid指向right, 如果此时mid的位置==target, 应该让right = mid, right并没有发生变化, 此时判断left还是<right, 就会形成死循环!!!
  • 上述, 就是二分查找的第二种类型: 查找元素的第一个位置
  • 同理, 要找元素的最后一个位置,假设一个位置为x,
    • 如果这个数>target, 说明 [left,x-1] 是我们要找的位置, [x,right] 可以舍去, 让right =mid-1,
    • 如果这个数==target, 说明[left,x-1] 可以舍去, [x,right] 是我们要找的位置, 让left = mid,
    • 如果这个数<target, 说明[left,x] 可以舍去, [x+1,right] 是我们要找的位置, 让left = mid+1
    • (因为当这个数<= target时, 我们都移动left, 所以可以合并, 但是left只能=mid)
  •  细节:
    • 1. 判断循环的条件, 一定是left < right , 不能写=  原因同上
    • 2. 求中点的操作, 一定是 int mid = left + (right - left + 1)/2
      • 那么此时, 如果我们选择向下取整, 即int mid = left + (right-left)/2, 那么当下面这种情况出现时, 此时mid指向left, 如果此时mid的位置==target, 应该让left = mid, left并没有发生变化, 此时判断left还是<right, 就会形成死循环!!!
  • 上述, 就是二分查找的第三种类型: 查找元素的最后一个位置

代码: 

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

相关推荐

0 条评论