hot100—65.在排序数组中查找元素的第一个和最后一个位置

文字题解
方法一:二分查找
直观的思路肯定是从前往后遍历一遍。用两个变量记录第一次和最后一次遇见 target 的下标,但这个方法的时间复杂度为 O(n),没有利用到数组升序排列的条件。

由于数组已经排序,因此整个数组是单调递增的,我们可以利用二分法来加速查找的过程。

考虑 target 开始和结束位置,其实我们要找的就是数组中「第一个等于 target 的位置」(记为 leftIdx)和「第一个大于 target 的位置减一」(记为 rightIdx)。

二分查找中,寻找 leftIdx 即为在数组中寻找第一个大于等于 target 的下标,寻找 rightIdx 即为在数组中寻找第一个大于 target 的下标,然后将下标减一。两者的判断条件不同,为了代码的复用,我们定义 binarySearch(nums, target, lower) 表示在 nums 数组中二分查找 target 的位置,如果 lower 为 true,则查找第一个大于等于 target 的下标,否则查找第一个大于 target 的下标。

最后,因为 target 可能不存在数组中,因此我们需要重新校验我们得到的两个下标 leftIdx 和 rightIdx,看是否符合条件,如果符合条件就返回 [leftIdx,rightIdx],不符合就返回 [−1,−1]。


1 / 14
C++
Java
JavaScript
Golang
C
class Solution { 
public:
    int binarySearch(vector& nums, int target, bool lower) {
        int left = 0, right = (int)nums.size() - 1, ans = (int)nums.size();
        while (left <= right) {
            int mid = (left + right) / 2;
            if (nums[mid] > target || (lower && nums[mid] >= target)) {
                right = mid - 1;
                ans = mid;
            } else {
                left = mid + 1;
            }
        }
        return ans;
    }

    vector searchRange(vector& nums, int target) {
        int leftIdx = binarySearch(nums, target, true);
        int rightIdx = binarySearch(nums, target, false) - 1;
        if (leftIdx <= rightIdx && rightIdx < nums.size() && nums[leftIdx] == target && nums[rightIdx] == target) {
            return vector{leftIdx, rightIdx};
        } 
        return vector{-1, -1};
    }
};
复杂度分析

时间复杂度: O(logn) ,其中 n 为数组的长度。二分查找的时间复杂度为 O(logn),一共会执行两次,因此总时间复杂度为 O(logn)。

空间复杂度:O(1) 。只需要常数空间存放若干变量。

下一篇题解
【视频讲解】二分查找总是写不对?三种写法,一个视频讲透!(Python/Java/C++/C/Go/JS)
评论 (703)

排序:最热

评论


Thirsty Margulis4Nt
2025.04.16
我一个面嵌入式的居然碰到这题了。这题一眼二分查找,但是真正写起来才发现有这么多暗坑。除了开闭区间的处理之外,还有中点赋值的数值溢出问题。比如说上面官方题解里的mid=(left+right)/2就是有风险的,应该改为mid=left+(right-left)/2才能避开风险。

5
1


爱做梦的鱼
2023.04.14
大家不要太纠结,搞两次正常的二分查找就好了,不要想什么大于等于,什么大于,就是等于,就找等于的

 
 // 两次二分查找,分开查找第一个和最后一个
  // 时间复杂度 O(log n), 空间复杂度 O(1)
  // [1,2,3,3,3,3,4,5,9]
  public int[] searchRange2(int[] nums, int target) {
    int left = 0;
    int right = nums.length - 1;
    int first = -1;
    int last = -1;
    // 找第一个等于target的位置
    while (left <= right) {
      int middle = (left + right) / 2;
      if (nums[middle] == target) {
        first = middle;
        right = middle - 1; //重点
      } else if (nums[middle] > target) {
        right = middle - 1;
      } else {
        left = middle + 1;
      }
    }

    // 最后一个等于target的位置
    left = 0;
    right = nums.length - 1;
    while (left <= right) {
      int middle = (left + right) / 2;
      if (nums[middle] == target) {
        last = middle;
        left = middle + 1; //重点
      } else if (nums[middle] > target) {
        right = middle - 1;
      } else {
        left = middle + 1;
      }
    }

    return new int[]{first, last};
  }
展开全部
1.6K
179


CLLLL
2025.03.25
返回的l永远是首个大于等于target的数的位置,r永远是首个小于target的数的位置,左边界按正常查找,右边查target+0.5即可

class Solution {
public:
    vector searchRange(vector& nums, int target) {
        if(nums.size()==0) return {-1,-1};
        int l=binSelect(nums,target);
        int r=binSelect(nums,target+0.5)-1;
        if( l>=nums.size() || r<0 || l>r){
            return {-1,-1};
        }
        return {l,r};
    }
    int binSearch(vector& nums, double target){
        int n=nums.size();
        int l=0,r=n-1;
        while(l<=r){
            int mid=l+(r-l)/2;
            if(nums[mid]>=target){
                r=mid-1;
            }else{
                l=mid+1;
            }
        }
        return l;
    }
};
展开全部

作者:力扣官方题解
链接:https://leetcode.cn/problems/find-first-and-last-position-of-element-in-sorted-array/solutions/504484/zai-pai-xu-shu-zu-zhong-cha-zhao-yuan-su-de-di-3-4/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(算法,数据结构,排序算法,leetcode,java,kafka)