在有序数组中查找元素的第一个和最后一个位置

160 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第10天,点击查看活动详情

1、前言

每天一个算法小练习,本篇使用Java实现。

2、题目描述

  给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值 target,返回 [-1, -1]。你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

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

2.1、示例1

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

2.2、示例2

输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1]

2.3、示例3

输入:nums = [], target = 0
输出:[-1,-1]

3、解题思路

3.1、二分查找

给的数组是有序的,最直接的我们可以从头到尾遍历一次,就能找到开始和结束的位置。但这样时间复杂度为O(N)O(N),就不符合题目要求了。我们可以使用二分查找,二分查找的时间复杂度为O(logn)O(log n)。可以先找左边界,即首个等于 target 值的数,且它的前一个值部位 target,右边界即等于 target 值,同时后一个数不等于target。

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = 0;
        int right = nums.length-1;
        //中间位置
        int mid = (left + right) >> 1;
        int num[] = new int[2];
        num [0] = -1;
        num [1] = -1;
        int i =0;
        while (left <= right) {
            if((i == 0 && nums[mid] == target && ( mid == 0 || nums[mid-1] != target))||(i == 1 && nums[mid] == target && (mid == end || nums[mid+1] != target ))) {
                num[i++] = mid;
                mid = (start + end)>>1;
            } else if(nums[mid] > target){
                end = mid-1;
            }else if(nums[mid] < target){
                start = mid+1;
            }else if(i == 0){
                //找左边界
                mid = mid -1;
            }else if(i == 1){
                //找右边界
                mid = mid + 1;
            }
            if(nums[mid] != target){
                mid = (start+end)>>1;
            }
            if(i == 2) {
                break;
            }
        }
        return nums;
    }
} 

执行结果:

image.png

  • 时间复杂度:O(logn)O(log n),n为数组的长度,因为二分查找的时间复杂度为O(logn)O(log n)

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

好了、本期就先介绍到这里,有什么需要交流的,大家可以随时私信我。😊