![00aa015187c98e3c07f49adb7a6b84d2.png](https://i-blog.csdnimg.cn/blog_migrate/9d06822c5649c71d75a779b7da6a9191.jpeg)
题目
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
你的算法时间复杂度必须是 O(log n) 级别。
如果数组中不存在目标值,返回 [-1, -1]。
示例 1
输入: nums = [5,7,7,8,8,10], target = 8
输出: [3,4]
示例 2
输入: nums = [5,7,7,8,8,10], target = 6
输出: [-1,-1]
卒!!!
官方解答
方法 1:线性扫描
想法
对 target 检查每一个下标,一定能得到正确答案。
算法
首先,我们对 nums 数组从左到右做线性遍历,当遇到 target 时中止。如果我们没有中止过,那么 target 不存在,我们可以返回“错误代码” [-1, -1] 。如果我们找到了有效的左端点坐标,我们可以坐第二遍线性扫描,但这次从右往左进行。这一次,第一个遇到的 target 将是最右边的一个(因为最左边的一个存在,所以一定会有一个最右边的 target)。我们接下来只需要返回这两个坐标。
class
复杂度分析
时间复杂度: O(n) 。
这个暴力解法检测了num 数组中每个元素恰好两次,所以总运行时间是线性的。
空间复杂度: O(1) 。
线性扫描方法使用了固定大小的数组和几个整数,所以它的空间大小为常数级别的。
方法 2:二分查找
想法
因为数组已经排过序了,我们可以使用二分查找的方法去定位左右下标。
算法
总体算法工作过程与线性扫描方法类似,除了找最左和最右下标的方法。这里我们仅仅做几个微小的调整,用这种修改过的二分查找方法去搜索这个排过序的数组。首先,为了找到最左边(或者最右边)包含 target 的下标(而不是找到的话就返回 true ),所以算法在我们找到一个 target 后不能马上停止。我们需要继续搜索,直到 lo == hi 且它们在某个 target 值处下标相同。
另一个改变是 left 参数的引入,它是一个 boolean 类型的变量,指示我们在遇到 target == nums[mid] 时应该做什么。如果 left 为 true ,那么我们递归查询左区间,否则递归右区间。考虑如果我们在下标为 i 处遇到了 target ,最左边的 target 一定不会出现在下标大于 i 的位置,所以我们永远不需要考虑右子区间。当求最右下标时,道理同样适用。
![3a28457960d1b685dea4fba3659f4566.png](https://i-blog.csdnimg.cn/blog_migrate/8150c5d4f200708a9fcbbc32cb5f20bd.png)
![8f10916a8250eb459d9ce713b7847330.png](https://i-blog.csdnimg.cn/blog_migrate/95319754609b0629eb78adfbfaf3c05a.png)
![a7d7a3158a0fbd6737716f0c9c2ccd04.png](https://i-blog.csdnimg.cn/blog_migrate/3b7b8932ec1778386a2105c65c16b035.png)
![d62fa082dd0002cfdb907b204007f111.png](https://i-blog.csdnimg.cn/blog_migrate/9846a6bd63fd47c614f645d473b4faf7.png)
![4ae3b4efd1799208fac2e7f6e1091e5c.png](https://i-blog.csdnimg.cn/blog_migrate/d441e14d1d47eae87ffa5621bcedf618.png)
![86416a16310c51e64c572a1ce2cabe89.png](https://i-blog.csdnimg.cn/blog_migrate/343956f86ddfafb07f5bac5b0ccae972.png)
![c11f781bbf164d54140da9a0440db213.png](https://i-blog.csdnimg.cn/blog_migrate/d42b3b1d9335e2b1dc6a2fd76a37dec9.png)
![6b539a40ad9b48629b26f5c399b51a0e.png](https://i-blog.csdnimg.cn/blog_migrate/0de8dfbe25f08646bc6e4d9d152a2d3a.png)
![342104533623ef4f806213051b480d09.png](https://i-blog.csdnimg.cn/blog_migrate/583216669cd16ef1647df4459294aeec.png)
![54d3b84eb917a98292c149bb9e670b4f.png](https://i-blog.csdnimg.cn/blog_migrate/94f1da1e03b8f2b5ed7c02793b63ae86.png)
![3a28457960d1b685dea4fba3659f4566.png](https://i-blog.csdnimg.cn/blog_migrate/8150c5d4f200708a9fcbbc32cb5f20bd.png)
![8f10916a8250eb459d9ce713b7847330.png](https://i-blog.csdnimg.cn/blog_migrate/95319754609b0629eb78adfbfaf3c05a.png)
![a7d7a3158a0fbd6737716f0c9c2ccd04.png](https://i-blog.csdnimg.cn/blog_migrate/3b7b8932ec1778386a2105c65c16b035.png)
![104f7e60fef0fd1905127247fba2ac4f.png](https://i-blog.csdnimg.cn/blog_migrate/9ae2561c14328b302a0de8d42d4e94b8.png)
![846ee2abcf3b01b52dba9147c1a5e36f.png](https://i-blog.csdnimg.cn/blog_migrate/386fd8ad1d2f4f3663f395465cabdd1a.png)
![7bf5a40c8904f125118bb7f56717081d.png](https://i-blog.csdnimg.cn/blog_migrate/781f9bec826e6a8e6d23bfd6279eb632.png)
![c7987053b875271a2098318aab3ba9ad.png](https://i-blog.csdnimg.cn/blog_migrate/c8774ead1caaf407130fb1bb52d51bd9.png)
![0be82354ea93526e9b99894462493e7c.png](https://i-blog.csdnimg.cn/blog_migrate/5e5951410871559e8ee0a1988a495a21.png)
![4312ac754532e1567663e8873c727536.png](https://i-blog.csdnimg.cn/blog_migrate/79ad9c2deec4b56b117e39805e6588e5.png)
![6e1d5156a06b32a0c647810ba56d151a.png](https://i-blog.csdnimg.cn/blog_migrate/1388532b236d1f3cee3cdfe971ae18f0.png)
class
复杂度分析
时间复杂度:O(log_2n) 。
由于二分查找每次将搜索区间大约划分为两等分,所以至多有 log_2n⌉ 次迭代。二分查找的过程被调用了两次,所以总的时间复杂度是对数级别的。
空间复杂度:O(1) 。
所有工作都是原地进行的,所以总的内存空间是常数级别的。