sisterAn / JavaScript-Algorithms

基础理论+JS框架应用+实践,从0到1构建整个前端算法体系

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

腾讯&字节&leetcode34:在排序数组中查找元素的第一个和最后一个位置

sisterAn opened this issue · comments

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

你的算法时间复杂度必须是 O(logn) 级别。

如果数组中不存在目标值,返回 [-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]

附赠leetcode地址:leetcode

commented
var searchRange = function(nums, target) {
  let left = 0, right = nums.length -1
  let start = -1, end = -1
  while(left <= right) {
      if(nums[left] < target) left++
      // 找到第一个出现的位置,赋值给start
      if(nums[left] === target && start === -1) start = left++
      if(nums[right] > target) right--
      // 找到最后一个出现的位置,赋值给end
      if(nums[right] === target && end === -1) end = right--
      if(start > -1 && end > -1) break
  }
  return [start, end]
};

解答一:findIndex、lastIndexOf

findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。若没有找到对应元素则返回-1。

lastIndexOf() 方法返回指定元素(也即有效的 JavaScript 值或变量)在数组中的最后一个的索引,如果不存在则返回 -1。

解答二:二分查找

let searchRange = function(nums, target) {
    return [leftSearch(nums, target), rightSearch(nums, target)]
}

let leftSearch = function(nums, target) {
    let low = 0, 
        high = nums.length - 1,
        mid
    while (low <= high) {
        mid = Math.floor((low+high)/2)
        if (nums[mid] < target) {
            low = mid + 1
        } else if (nums[mid] > target) {
            high = mid - 1
        } else if (nums[mid] === target) {
            // 这里不返回,继续收缩左侧边界
            high = mid - 1
        }
    }
    // 最后检查 low 是否越界或命中
    if (low >= nums.length || nums[low] != target)
        return -1
    return low
}


let rightSearch = function (nums, target) {
    let low = 0, 
        high = nums.length - 1,
        mid
    while (low <= high) {
        mid = Math.floor((low+high)/2)
        if (nums[mid] < target) {
            low = mid + 1
        } else if (nums[mid] > target) {
            high = mid - 1
        } else if (nums[mid] === target) {
            // 这里不返回,继续收缩右侧边界
            low = mid + 1
        }
    }
    // 最后检查 high 是否越界或命中
    if (high < 0 || nums[high] != target)
        return -1
    return high
}

复杂度分析:

  • 时间复杂度:O(logn) 
  • 空间复杂度:O(1)

嗯,这算法可以, 但是在真正项目中我愿意用 findIndex , findLastIndex

commented
###  const comfiles = (arr, val) => {
    let sta = -1, end = -1;
    let obj = {}
    arr.forEach((item, index) => {
      if (item === val) {
        if (obj[item]) {
          end = index
        } else {
          obj[item] = index
          sta = index
        }
      }
    })
    return [sta, end]
  }

简化的二分查找

var searchRange = function(nums, target) {
  let mid;
  let low = 0;
  let high = nums.length - 1;

  while (low <= high) {
    mid = Math.floor((low + high) / 2);
    if (nums[mid] === target) {
      let start = end = mid;
      while (nums[start] === target) start--;
      while (nums[end] === target) end++;

      return [start + 1, end - 1];
    }

    if (nums[mid] > target) {
      high = mid - 1;
    } else {
      low = mid + 1;
    }
  }

  return [-1, -1];
}

二分查找找到后,双指针同时向前向后查找。