算法练习第44题-在排序数组中查找元素的第一个和最后一个位置

295 阅读3分钟

一、题目

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?  

示例 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]

作者:力扣 (LeetCode) 链接:leetcode-cn.com/leetbook/re…

来源:力扣(LeetCode) 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

二、思路

暴力解法

  • 暴力解法
  • 返回目标值在数组中的开始位置和结束位置
  • 在数组不存在目标值的情况下,返回[-1,-1]
  • 因此默认开始位置和结束位置为left = -1, right = -1
  • 两个for循环,第一个for循环找left,找到后退出,
  • 第二个for循环找right,找到后退出循环
  • 找到没有找到,最后都return [left, right]

二分查找

  • 根据暴力解法可知,首先要找到开始位置lindex值,
  • 再查找rindex值
  • 定义len = nums.length, left = 0, right = len - 1, result = nums.length
  • 循环条件是left <= right
  • 中间值: mid = Math.floor((left + right)/ 2)
  • 这里可以思考一个问题,什么时候能拿到lindex值,当nums[mid]>= target时,就拿到了lindex
  • 满足条件 right = mid -1 , result = mid
  • 否则left = mid + 1,最后当条件不满足时,返回结果
  • 这是思考rindex的求值方式,其实当nums[mid]> target时,mid - 2 就是rindex的坐标了
  • 由于两个高度相似,因此提取代码
  • 定义coordinate = (nums, target, seat)
  • 最后还要做下判断
  • 如果nums[lindex] === target为真,那么就是有开始位置和结束位置
  • 否则返回[-1, -1]

三、代码

暴力解法的代码

let searchRange = function(nums, target) {
  /**
   * 暴力解法
   * 返回目标值在数组中的开始位置和结束位置
   * 在数组不存在目标值的情况下,返回[-1,-1]
   * 因此默认开始位置和结束位置为left = -1, right = -1
   * 两个for循环,第一个for循环找left,找到后退出,
   * 第二个for循环找right,找到后退出循环
   * 找到没有找到,最后都return [left, right]
   * **/ 
  let len = nums.length, left = -1, right = -1
  for(let i = 0; i < len; i++) {
   if (nums[i] == target) {
      left = i
      break 
   }
  }
  for(let i = len; i > -1; i--) {
    if (nums[i] == target) {
      right = i
      break 
    }
  }
  return [left, right]
}

二分查找解法

// let nums = [5,7,7,8,8,10], target = 8
// let nums = [5,7,7,8,8,10], target = 6
// let nums = [], target = 0
let nums = [1], target = 1
// let nums = [1,2], target = 1
// let nums = [3,3,3], target = 3
let searchRange = function(nums, target) {
  /**
   * 二分查找
   * 根据暴力解法可知,首先要找到开始位置lindex值,
   * 再查找rindex值
   * 定义len = nums.length, left = 0, right = len - 1, result = nums.length
   * 循环条件是left <= right
   * 中间值: mid = Math.floor((left + right)/ 2)
   * 这里可以思考一个问题,什么时候能拿到lindex值,当nums[mid]>= target时,就拿到了lindex
   * 满足条件 right = mid -1 , result = mid
   * 否则left = mid + 1,最后当条件不满足时,返回结果
   * 这是思考rindex的求值方式,其实当nums[mid]> target时,mid - 2 就是rindex的坐标了
   * 由于两个高度相似,因此提取代码
   * 定义coordinate = (nums, target, seat)
   * 最后还要做下判断
   * 如果nums[lindex] === target为真,那么就是有开始位置和结束位置
   * 否则返回[-1, -1]
   * 
   * */ 

  let lindex = coordinate(nums, target, 'left')
  let rindex = coordinate(nums, target, 'right') - 1
  if (nums[lindex] === target) return [lindex, rindex]
  return [-1, -1]
 
}
const coordinate = (nums, target, seat) => {
  let len = nums.length, left = 0, right = len - 1, result = nums.length
  while(left <= right) {
    const mid = Math.floor((left + right) / 2)
    const midNum = nums[mid]
    const state = seat === 'left' ? (midNum >= target):(midNum > target)
    if (state) {
      right = mid - 1
      result = mid
    } else {
      left = mid + 1
    }
  }
  return result
}

searchRange(nums, target)

四、测试结果

暴力解法

image.png

二分查找

image.png