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

217 阅读2分钟

前言

你好, 我是Cici。我一直觉得自己的算法是短板,所以打算自己重新系统的刷一刷,谈谈自己的思路,说说自己的思考,加强自己的同时也希望能给大家带来帮助。其实数据结构和算法属于我们技术人员的内功,不管技术怎么更新,它始终都是不变的。
同类题目推荐:

一、问题描述

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

观察题目,我们可以得到的关键信息有:

  • nums 是一个非递减数组
  • 要求的时间复杂度为 O(log n)
  • 要找到两个值:开始位置 和 结束位置

二、题目分析

由关键信息,我们首先考虑使用二分查找法来解决问题
分析题目,最终的结果有三种情况:

  1. target 在数组范围中且数组中不存在 target,例如 nums = [5, 7, 8, 10],target = 6,此时返回 [-1, -1]。
  2. target 在数组范围中且数组中存在 target,例如 nums = [5, 7, 8, 10],target = 8,此时返回 [2,2]。
  3. target 不在数组范围中,在数组的左右两侧,例如 nums = [5, 7, 8, 10],target = 4 或者 target = 11,此时返回 [-1, -1]。

解题思路:

  1. 第一次二分查找,寻找 target 的左边界
  2. 第二次二分查找,寻找 target 的右边界
  3. 根据这两次查找的结果,结合上面分析的三种情况,返回最终结果。

image.png

三、参考代码

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = findLeft(nums, target);
        int right = findRight(nums, target);
        // 三种情况
        if(left == -2 || right == -2){
            return new int[]{-1, -1};
        }
        if(right - left > 1){
            return new int[]{left + 1, right - 1};
        }
        return new int[]{-1, -1};
    }
    public int findLeft(int[] nums, int target){ //寻找左边界
        int left = 0;
        int right = nums.length - 1;
        int temp = -2; //辅助值,用于返回结果
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] >= target){
                right = mid - 1;
                temp = right;
            }else{
                left = mid + 1;
            }
        }
        return temp;
    }
    public int findRight(int[] nums, int target){ //寻找右边界
        int left = 0;
        int right = nums.length - 1;
        int temp = -2;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(nums[mid] <= target){
                left = mid + 1;
                temp = left;
            }else{
                right = mid - 1;
            }
        }
        return temp;
    }
}