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

知识点:数组,二分查找

题目描述

给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。

如果数组中不存在目标值 target,返回 [-1, -1]。

进阶:

你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?

示例
输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4] 输入:nums = [5,7,7,8,8,10], target = 6
输出:[-1,-1] 输入:nums = [], target = 0
输出:[-1,-1]

解法一:二分查找

这是一道典型的二分查找的问题,只不过这次需要我们返回左右边界。

在基础的二分法也就是35题基础上,做些修改。依次找到左右边界。

  • 寻找左边界:有两种情况
  1. 如果整个数组中没有target的值,那最后返回的就是第一个比target大的元素位置的索引;
  2. 如果找到了target的值,不能停,左边界可能还有值,需要将搜索区间移动到mid左边,即right=mid-1;这时候会出现两种情况:
    • 1.在左区间又找到了target。
    • 2.在左区间没有target了。

      要清楚的是最后一次执行的一定是left=right=mid,而且mid左侧都小于target,mid右侧的值都大于等于target,如果判断mid这时候的值也小于target,那left=mid+1,正好就是第一个等于target的值。
  • 寻找右边界:有两种情况
  1. 如果整个数组中没有target的值,那最后返回的就是第一个比target小的位置的索引;
  2. 如果找到了target的值,不能停,右边界可能还有值,需要将搜索区间移动到mid右边,即leftt=mid+1;这时候会出现两种情况:
    • 1.在右区间又找到了target。
    • 2.在右区间没有target了。

      要清楚的是最后一次执行的一定是left=right=mid,而且mid左侧都小于等于target,mid右侧的值都大于target,如果判断mid这时候的值大于target,那right=mid-1,正好就是第一个等于target的值。

总的来说(关键)

  • 左边界其实就是在找第一个>=target的位置

    • 如果数组中有target,返回就是第一个target的位置;
    • 如果数组中无target,返回就是第一个比target大的元素是位置(或者可以理解成要插入target的位置);
  • 右边界其实就是在找最后一个<=target的位置
    • 如果数组中有target,返回就是最后target的位置;
    • 如果数组中无target,返回就是最后一个小于target的位置(或者可以理解成要插入的target的位置的前一个位置)。

所以最后就可以直接比较left和right的位置了,如果left比right还大,那证明不存在了。

class Solution {
public int[] searchRange(int[] nums, int target) {
int left = leftBound(nums, target);
int right = rightBound(nums, target);
while(left > right) return new int[]{-1, -1};
return new int[] {left, right};
}
private int leftBound(int[] nums, int target){
int left = 0, right = nums.length-1;
while(left <= right){
int mid = left + ((right-left) >> 1);
if(target <= nums[mid]){ //将等于合并过来;
right = mid-1;
}else{
left = mid+1;
}
}
return left; //第一个比大于等于target的索引;
}
private int rightBound(int[] nums, int target){
int left = 0, right = nums.length-1;
while(left <= right){
int mid = left + ((right-left) >> 1);
if(target >= nums[mid]){
left = mid+1;
}else{
right = mid-1;
}
}
return right;
}
}

体会

注意去思考里面的细节,思考左右边界是如何获取到的。要抓住最关键的:最后一次执行的一定是left=mid=right,三个是同一个数,而且mid左侧都比目标值小,mid右侧都比目标值大,这时候就看mid值,如果比t大,那执行right=mid-1;返回left就是正好当前值,当前值比t大,当然也可能包括t;如果比t小,那执行left=mid+1;返回的left移动一位就比t大了。

【LeetCode】34. 在排序数组中查找元素的第一个和最后一个位置的更多相关文章

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

    在排序数组中查找元素的第一个和最后一个位置 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n ...

  2. LeetCode 34 - 在排序数组中查找元素的第一个和最后一个位置 - [二分][lower_bound和upper_bound]

    给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...

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

    class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { ve ...

  4. Leetcode题目34.在排序数组中查找元素的第一个和最后一个位置(中等)

    题目描述: 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标 ...

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

    题目描述 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值 ...

  6. 【LeetCode】在排序数组中查找元素的第一个和最后一个位置【三次二分】

    给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...

  7. 34、在排序数组中查找元素的第一个和最后一个位置 | 算法(leetode,附思维导图 + 全部解法)300题

    零 标题:算法(leetode,附思维导图 + 全部解法)300题之(34)在排序数组中查找元素的第一个和最后一个位置 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: / ...

  8. Leetcode题库——34.在排序数组中国查找元素的第一个和最后一个位置

    @author: ZZQ @software: PyCharm @file: searchRange.py @time: 2018/11/12 19:19 要求:给定一个按照升序排列的整数数组 num ...

  9. #leetcode刷题之路34-在排序数组中查找元素的第一个和最后一个位置

    给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置.你的算法时间复杂度必须是 O(log n) 级别.如果数组中不存在目标值,返回 [-1 ...

随机推荐

  1. JavaScript的核心语法

    1.JavaScript同其他程序设计语言一样,有着独特的语法结构,主要包含:变量.数据类型.运算符号.控制语句和注释等. 2.变量是存储数据的基本单位,JavaScript通常利用变量来参与j各种运 ...

  2. Etcd中linearizable read实现

    linearizable 有点疑惑,不确定是现在浏览的版本没开发完全,还是没有按照论文的linearizable来实现. 按照论文所说,在客户端请求的时候,实际上是一个强一致的 exactly onc ...

  3. 使用Spring Data JPA 访问 Mysql 数据库-配置项

    jpa操作数据库 注意:数据库采用的是本机数据库,下面是建表语句及初始化数据: SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------- ...

  4. 什么IP欺骗?

    1.什么是IP欺骗? IP欺骗是指创建源地址经过修改的Internet协议(IP) 数据包,目的要么是隐藏发送方的身份,要么是冒充其他计算机系统,或者两者兼具.恶意用户往往采用这项技术对目标设备或周边 ...

  5. 如何使用「mkvtoolnix」和「GoldWave」仅保留视频中左、右声道的其中一个声道?

    为什么要这样做? 我手上有一部电视剧的视频文件(.rmvb),每个视频文件都是"国/粤双语"的,与其他双语视频的两种语言的音频保存在两个音轨上不同,我这里的视频文件的双语是分别保存 ...

  6. js 正则表达式 验证数字或字母

    let reg= /^(^[0-9]*$)|(^[A-Za-z]+$)/ /*reg= /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]$/*/ if(!reg.test( ...

  7. 调整/home和/root空间容量

    转载请注明出处:http://www.cnblogs.com/gaojiang/p/6767043.html 1.查看磁盘情况:df -h 2.卸载/homeumount /home umount / ...

  8. 在Redis中设置了过期时间的Key,需要注意哪些问题?

    熟悉Redis的同学应该知道,Redis的每个Key都可以设置一个过期时间,当达到过期时间的时候,这个key就会被自动删除. 在为key设置过期时间需要注意的事项 1. DEL/SET/GETSET等 ...

  9. MySql数据库缓存

    对MySql查询缓存及SQL Server过程缓存的理解及总结 一.MySql的Query Cache 1.Query Cache   MySQL Query Cache是用来缓存我们所执行的SELE ...

  10. git常用命令自己梳理总结

    一.新建代码库 # git-init - 创建一个空的 Git 存储库或重新初始化一个现有的存储库 $ git init # 在本地新建一个repo,进入一个项目目录,执行git init,会初始化一 ...