从零刷算法-在排序数组中查找元素的第一个和最后一个位置

94 阅读1分钟

「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」。

题目描述

给定一个按照升序排列的整数数组 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]

提示:

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

题目链接:在排序数组中查找元素的第一个和最后一个位置

思路介绍

题意分析

很容易看出来是二分查找,尤其是进阶要求O(log n),就可以百分百确定是使用二分查找了。 二分查找思想并不难,难点在细节。 大于还是大于等于?向上取整还是向下?缩进区间是加一减一还是不变?最终结果到底是左边界还是右边界?

在进行二分查找时,low会增大,high会减小。如果循环条件是low<=high,则循环结束时high在low前面。要找右边的某个数时,要借助low实现,因为low会不断变大。要找左边的某个数时,要借助high实现,因为high会不断变小。要找=target的最左边的数时,也就是找满足>=target的最左边的数。但是,当nums[mid]>=target时,无法判断nums[mid]是否是满足nums[mid]>=target的最左边的数。所以不能让high = mid。但是,当nums[mid]>=target时,可以判断nums[mid]是满足nums[mid]>=target的数。所以,让high = mid - 1。这样,只要满足条件,high就变小,最终high会停在第一个不满足条件的点。所以,当nums[mid]>=target时, high = mid - 1。这样,最终high就会停在第一个不满足>=target的地方。同理,要找=target的最右边的数时,也就是找<=target的最右边的数。所以,当nums[mid]<=target时, low = mid + 1。这样,最终low就会停在第一个不满足<=target的地方。

代码

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

运行结果

执行结果:通过

执行用时:0 ms,

内存消耗:44.3 MB

\