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

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

1. 题目描述

给你一个按照 非递减顺序 排列的整数数组 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 34)

2. 题目分析

题目描述十分清晰,给你一个数组,让你找到目标值 target 的开始和结束位置。很显然数组中可能出现多个 target ,我们的目标是找到 第一个 出现 target 的下标和 最后一个 出现 target 的下标。我们很容易想到一个方法,直接遍历一遍数组找到 target 。但题目给了一个关键要求,算法时间复杂度必须是 O(log n) 。看到 查找O(log n) ,可以断定此题必然是一个经典的 二分查找

3. 二分查找

什么是二分查找?

实质上就是对要查找的数组,从中间开始向头部和尾部进行查找,判断条件是目标值 target 和中间值 mid 进行比较,若 target > mid,则 target 必然在 mid 右侧,反之则在左侧,这就要求查找的数组是有序的,以升序为例

实现代码如下:

public int binarySearch(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
     
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (target < nums[mid]){
                right = mid - 1;
            }else if (nums[mid] < target) {
                left = mid + 1;
            }
            else 
                return mid;    
        }
        return -1;
 }

但二分查找只是找到了 target ,至于是第一个还是最后一个亦或中间的就不得而知了,在此基础上,我们需要对代码进行一些改进…

4. searchLeft 和 searchRight

searchLeft 即找到目标 target 最左边下标,searchRight 即找到目标 target 最右边下标,以searchLeft为例
实现代码如下:

public int searchLeft(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int flag = -1;
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (target < nums[mid]){
                right = mid - 1;
            }else if (nums[mid] < target) {
                left = mid + 1;
            }
            else {
                flag = mid;
                right = mid - 1;
            }
        }
        return flag;
 }

其实就是在找到 target 后不返回值,继续查找,直到最左侧没有 target,searchRight 也是同样的思路。

5. 整体的代码实现

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int[] arr = new int[]{searchLeft(nums,target),searchRight(nums,target)};
        return arr;
    }

 public int searchLeft(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int flag = -1;
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (target < nums[mid]){
                right = mid - 1;
            }else if (nums[mid] < target) {
                left = mid + 1;
            }
            else {
                flag = mid;
                right = mid - 1;
            }
        }
        return flag;
 }
 public int searchRight(int[] nums, int target) {
        int left = 0;
        int right = nums.length - 1;
        int flag = -1;
        while (left <= right){
            int mid = (left + right) >>> 1;
            if (target < nums[mid]){
                right = mid - 1;
            }else if (nums[mid] < target) {
                left = mid + 1;
            }
            else {
                flag = mid;
                left = mid + 1;
            }
        }
        return flag;
 }
 
 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值