【LeetCode刷题】NO.11

113 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一.题目

34. 在排序数组中查找元素的第一个和最后一个位置 给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]示例 1:

输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]

示例 2:

输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]

示例 3:

输入: nums = [], target = 0
输出: [-1,-1]

提示:

  • 0 <= nums.length <= 105
  • -109 <= nums[i] <= 109
  • nums 是一个非递减数组
  • -109 <= target <= 109

二、思路分析:

首先从题目开始分析题目中提出需要找出给定目标值再数组中的开始位置和结束位置,即如果在给定的升序数组中,如果有重复的target值,我们需要找到重复数字的最左边或者最右边的那个target的索引值,那么我们就需要在创建两个方法分别求出最左边的target值和最右边的target值。

求出目标值我们还是采用二分搜索的方法进行查找,但是我们只需要改变一些地方就能够达到题目的要求,一般的二分查找的框架是找到target值的时候就会返回结果,即return mid,这道题我们就可以改掉这一处的代码,以right = num.length - 1为例,我们在while的循环中的循环结束条件就为left <= right,如果right = num.length我们的循环条件就是left < right这个开区间,现在我们采用的是[left,right]闭区间,当寻找最左边target索引时,我们寻找到目标值后的操作从return mid改成right = mid - 1,以达到压缩到左半部分的效果,同理,如果我们寻找的是最右边target索引时,我们的代码就要改成left = mid + 1以达到压缩至右半部分的效果。

但是需要注意越界情况:在寻找最左边target位置的时候需要注意,while循环退出的条件是left = right + 1,所以当target值比数组所有元素都大时,left会越界所以我们需要进行left是否大于等于数组长度的判断,同理寻找最右边的target值我们需要考虑如果target值比所有的数组元素小right就在索引为-1的情况。

image.png

三、代码:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var searchRange = function(nums, target) {
    let res = [-1,-1]
    if(nums.length == 0) return res
    let leftindex = left_bound(nums,target)
    let rightindex = right_bound(nums,target)
    res = [leftindex,rightindex]
    return res
}
const left_bound = (nums,target) =>{
    let left = 0,right = nums.length - 1
    while(left <= right){
        let mid = Math.floor(left + (right - left)/2) 
        if(nums[mid] == target){
            right = mid - 1
        }else if(nums[mid] > target){
            right = mid - 1
        }else if(nums[mid] < target){
            left = mid + 1
        }
    }
    if(left >= nums.length || nums[left] != target) return -1
    return left
}
const right_bound = (nums,target) =>{
    let left = 0,right = nums.length - 1
    while(left <= right){
        let mid = Math.floor(left + (right - left)/2) 
        if(nums[mid] == target){
            left = mid + 1
        }else if(nums[mid] > target){
            right = mid - 1
        }else if(nums[mid] < target){
            left = mid + 1
        }
    }
    if(right <= -1 || nums[right] != target) return -1
    return right
}

四、总结:

到这里二分查找的诸多题目都应该能用这个框架做出来,基本的二分查找框架能够帮助我们快速找到目标值,对于压缩左半部分右半部分的变形框架可以帮助我们快速找到重复值的最左边以及最右边,这是从2号刷的第11题,希望自己能够再接再厉努力冲冲冲!