【LeetCode】34. 在排序数组中查找元素的第一个和最后一个位置
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题基础上,做些修改。依次找到左右边界。
- 寻找左边界:有两种情况
- 如果整个数组中没有target的值,那最后返回的就是第一个比target大的元素位置的索引;
- 如果找到了target的值,不能停,左边界可能还有值,需要将搜索区间移动到mid左边,即right=mid-1;这时候会出现两种情况:
- 1.在左区间又找到了target。
- 2.在左区间没有target了。
要清楚的是最后一次执行的一定是left=right=mid,而且mid左侧都小于target,mid右侧的值都大于等于target,如果判断mid这时候的值也小于target,那left=mid+1,正好就是第一个等于target的值。
- 寻找右边界:有两种情况
- 如果整个数组中没有target的值,那最后返回的就是第一个比target小的位置的索引;
- 如果找到了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. 在排序数组中查找元素的第一个和最后一个位置的更多相关文章
- Java实现 LeetCode 34 在排序数组中查找元素的第一个和最后一个位置
在排序数组中查找元素的第一个和最后一个位置 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n ...
- LeetCode 34 - 在排序数组中查找元素的第一个和最后一个位置 - [二分][lower_bound和upper_bound]
给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...
- leetcode 34在排序数组中查找元素的第一个和最后一个位置
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { ve ...
- Leetcode题目34.在排序数组中查找元素的第一个和最后一个位置(中等)
题目描述: 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标 ...
- 【LeetCode】34-在排序数组中查找元素的第一个和最后一个位置
题目描述 给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值 ...
- 【LeetCode】在排序数组中查找元素的第一个和最后一个位置【三次二分】
给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置. 你的算法时间复杂度必须是 O(log n) 级别. 如果数组中不存在目标值,返回 [ ...
- 34、在排序数组中查找元素的第一个和最后一个位置 | 算法(leetode,附思维导图 + 全部解法)300题
零 标题:算法(leetode,附思维导图 + 全部解法)300题之(34)在排序数组中查找元素的第一个和最后一个位置 一 题目描述 二 解法总览(思维导图) 三 全部解法 1 方案1 1)代码: / ...
- Leetcode题库——34.在排序数组中国查找元素的第一个和最后一个位置
@author: ZZQ @software: PyCharm @file: searchRange.py @time: 2018/11/12 19:19 要求:给定一个按照升序排列的整数数组 num ...
- #leetcode刷题之路34-在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target.找出给定目标值在数组中的开始位置和结束位置.你的算法时间复杂度必须是 O(log n) 级别.如果数组中不存在目标值,返回 [-1 ...
随机推荐
- SqlServer数据库分区
在最近的项目中,在尽可能优化了sql语句后,上层仍要求对数据库进行优化,因为考虑到系统上线后数据量会非常庞大,而且这些个表的数据都有明显的时间划分,于是就引入了数据库分区的概念.摘用百度百科的定义,数 ...
- Java-Java8特性(更新中)
Java8新特性 之前零零散散写了很多java8的内容,今天做一个整理,也算是整理用到的内容,当然细化的话还有很多,只是说暂时用不到,为了面试的话已经够了 日期计算 Lambda表达式 函数式接口(比 ...
- 快速简单的了解VLAN(VXLAN)和端口链路类型
目录 前言 一.VLAN是什么? 1.优点 2.为什么推出VXLAN 二.VXLAN又是什么? 1.优点 三.创建VLAN 四.介绍端口链路类型 五.Access 1.特性 六.Trunk 1.特性 ...
- Kubernetes在生产环境中的一些讨论
pod是所有一切资源的中心,毫无疑问是Kubernetes中最重要的资源.毕竟, 每个应用都运行在pod中.为了确保知道如何开发能充分利用应用所在环境资源的应用,最后再从应用的角度来仔细看一下pod. ...
- Linux中su和sudo的用法
su -#su - oldboy //当执行这个命令的时候表示切换到oldboy用户,并且重新读取用户环境相关配置文件,具体的来说就是执行下用户家目录下.bash_profile和.bashrc文件, ...
- MyBatis-HotSwap, MyBatis热部署
https://github.com/xiaochenxinqing/MyBatis-HotSwap 1 https://github.com/xiaochenxinqing/MyBatis-Ho ...
- (转发)forward与(重定向)redirect的区别
(转发)forward与(重定向)redirect的区别 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服 ...
- The Different of Python 2.x and 3.x
为了不给Python3.0带入过多的累赘,Python 3.x没有考虑向下兼容 1,print 函数 print语句没有了,取而代之的是print()函数. Python2.7 print " ...
- 微信app支付,完整流程,完整代码 (转)
微信app支付流程 需要的配置参数 private function wechat($body,$indent_id,$cou,$user_id,$total_fee,$ip,$domain,$non ...
- VS2017 常用快捷键
项目相关的快捷键 Ctrl + Shift + B = 生成项目 Ctrl + Alt + L = 显示 Solution Explorer(解决方案资源管理器) Shift + Alt+ C = 添 ...