【Leetcode刷题Python】34. 在排序数组中查找元素的第一个和最后一个位置(二分查找)

简介: 解决LeetCode "在排序数组中查找元素的第一个和最后一个位置" 问题的方法。第一种方法是使用两次二分查找,首先找到目标值的最左边界,然后找到最右边界。第二种方法是利用Python的list.index()方法,先正序找到起始位置,再逆序找到结束位置,并给出了两种方法的Python实现代码。

1 题目

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

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

你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。

示例 1:

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

输出:[3,4]

示例 2:

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

输出:[-1,-1]

2 解析

(1)方法一

两次二分查找

第一次查找起始位置:

1、二分的范围,l = 0l=0, r = nums.size() - 1r=nums.size()−1,我们去二分查找>=target>=target的最左边界。

2、当nums[mid] >= targetnums[mid]>=target时,往左半区域找,r = midr=mid。

3、当nums[mid] < targetnums[mid]<target时, 往右半区域找,l = mid + 1l=mid+1。

4、如果nums[r] != targetnums[r]!=target,说明数组中不存在目标值 targettarget,返回 [-1, -1][−1,−1]。否则我们就找到了第一个>=target>=target的位置LL。

第二次查找结束位置:

1、二分的范围,l = 0l=0, r = nums.size() - 1r=nums.size()−1,我们去二分查找<=target<=target的最右边界。

2、当nums[mid] <= targetnums[mid]<=target时,往右半区域找,l = midl=mid。

3、当nums[mid] > targetnums[mid]>target时, 往左半区域找,r = mid - 1r=mid−1。

4、找到了最后一个<=target<=target的位置RR,返回区间[L,R][L,R]即可。


二分查找的模板及使用方法

模板1

当我们将区间[l, r][l,r]划分成[l, mid][l,mid]和[mid + 1, r][mid+1,r]时,其更新操作是r = midr=mid或者l = mid + 1l=mid+1,计算midmid时不需要加11,即mid = (l + r)/2mid=(l+r)/2。

代码模板:

def bsearch_1( l,  r):
   while (l < r)
      mid = (l + r)/2;
      if (check(mid)):
          r = mid
      else:
          l = mid + 1;   
   return l;

模板2

当我们将区间[l, r][l,r]划分成[l, mid - 1][l,mid−1]和[mid, r][mid,r]时,其更新操作是r = mid - 1r=mid−1或者l = midl=mid,此时为了防止死循环,计算midmid时需要加11,即mid = ( l + r + 1 ) /2mid=(l+r+1)/2。

代码模板:

def bsearch_2( l,  r)
   while (l < r)
      mid = ( l + r + 1 ) /2
      if (check(mid)): 
          l = mid;
      else:
          r = mid - 1;
   return l;

(2)方法二

利用Python的返回索引的方法list.index()

第一次正序,第二次逆序

3 Python实现

(1)方法一

def searchRange(self, nums: List[int], target: int) -> List[int]:
        # 方法一:两个二分查找
        if target not in nums:
            return [-1,-1]
        l = 0
        r = len(nums)-1
        while l<r:
            mid = int((l+r)/2)
            if nums[mid]>=target:
                r = mid
            else :
                l = mid+1
        if nums[r] !=target:return [-1,-1]
        L  = l
        l,r = 0,len(nums)-1
        while l < r:
            mid = int((l+r+1)/2)
            if nums[mid] <= target:
                l = mid
            else:
                r = mid-1        
        return [L,r]

(2)方法二

def searchRange(self, nums: List[int], target: int) -> List[int]:
        # 方法二:两次顺序遍历
         if target not in nums:
             return [-1,-1]
         start = nums.index(target)
         nums.reverse()
         end = len(nums)-nums.index(target)-1
         return [start,end]
目录
相关文章
|
4月前
|
Java 数据处理 索引
(Pandas)Python做数据处理必选框架之一!(二):附带案例分析;刨析DataFrame结构和其属性;学会访问具体元素;判断元素是否存在;元素求和、求标准值、方差、去重、删除、排序...
DataFrame结构 每一列都属于Series类型,不同列之间数据类型可以不一样,但同一列的值类型必须一致。 DataFrame拥有一个总的 idx记录列,该列记录了每一行的索引 在DataFrame中,若列之间的元素个数不匹配,且使用Series填充时,在DataFrame里空值会显示为NaN;当列之间元素个数不匹配,并且不使用Series填充,会报错。在指定了index 属性显示情况下,会按照index的位置进行排序,默认是 [0,1,2,3,...] 从0索引开始正序排序行。
388 0
|
8月前
|
Go
【LeetCode 热题100】DP 实战进阶:最长递增子序列、乘积最大子数组、分割等和子集(力扣300 / 152/ 416 )(Go语言版)
本文深入解析三道经典的动态规划问题:**最长递增子序列(LIS)**、**乘积最大子数组** 和 **分割等和子集**。 - **300. LIS** 通过 `dp[i]` 表示以第 `i` 个元素结尾的最长递增子序列长度,支持 O(n²) 动态规划与 O(n log n) 的二分优化。 - **152. 乘积最大子数组** 利用正负数特性,同时维护最大值与最小值的状态转移方程。 - **416. 分割等和子集** 转化为 0-1 背包问题,通过布尔型 DP 实现子集和判断。 总结对比了三题的状态定义与解法技巧,并延伸至相关变种问题,助你掌握动态规划的核心思想与灵活应用!
352 1
|
Python
二分查找变种大赏!Python 中那些让你效率翻倍的搜索绝技!
二分查找是一种高效的搜索算法,适用于有序数组。其基本原理是通过不断比较中间元素来缩小搜索范围,从而快速找到目标值。常见的变种包括查找第一个等于目标值的元素、最后一个等于目标值的元素、第一个大于等于目标值的元素等。这些变种在实际应用中能够显著提高搜索效率,适用于各种复杂场景。
201 9
|
算法 数据处理 开发者
超越传统:Python二分查找的变种策略,让搜索效率再上新台阶!
本文介绍了二分查找及其几种Python实现的变种策略,包括经典二分查找、查找第一个等于给定值的元素、查找最后一个等于给定值的元素以及旋转有序数组的搜索。通过调整搜索条件和边界处理,这些变种策略能够适应更复杂的搜索场景,提升搜索效率和应用灵活性。
173 5
|
搜索推荐 Python
Leecode 101刷题笔记之第五章:和你一起你轻松刷题(Python)
这篇文章是关于LeetCode第101章的刷题笔记,涵盖了多种排序算法的Python实现和两个中等难度的编程练习题的解法。
181 3
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
199 0
Leetcode第三十三题(搜索旋转排序数组)
|
算法 C++ Python
Leecode 101刷题笔记之第四章:和你一起你轻松刷题(Python)
这篇博客是关于LeetCode上使用Python语言解决二分查找问题的刷题笔记,涵盖了从基础到进阶难度的多个题目及其解法。
161 0
|
算法 C++ Python
Leecode 101刷题笔记之第三章:和你一起你轻松刷题(Python)
本文是关于LeetCode算法题的刷题笔记,主要介绍了使用双指针技术解决的一系列算法问题,包括Two Sum II、Merge Sorted Array、Linked List Cycle II等,并提供了详细的题解和Python代码实现。
243 0
|
算法 C++ 索引
Leecode 101刷题笔记之第二章:和你一起你轻松刷题(Python)
本文是关于LeetCode 101刷题笔记的第二章,主要介绍了使用Python解决贪心算法题目的方法和实例。
161 0
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
291 0

推荐镜像

更多