首页 > 其他分享 >34. 在排序数组中查找元素的第一个和最后一个位置(中等)

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

时间:2024-07-06 20:26:51浏览次数:19  
标签:right target nums mid 34 查找 目标值 排序 left

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

  • 1. 题目描述
  • 2.详细题解
    • (1)朴素二分查找算法
    • (2)改进二分查找算法
  • 3.代码实现
    • 3.1 Python
      •   方法一:
      •   方法二:
      •   方法三:优化方法二
    • 3.2 Java

1. 题目描述

题目中转:34. 在排序数组中查找元素的第一个和最后一个位置
在这里插入图片描述
在这里插入图片描述

2.详细题解

(1)朴素二分查找算法

    在非递减(升序)数组中查找目标值的起始和结束位置,如果不存在则返回[-1,-1],最直观和直接的方法是依次遍历,第一次寻找到的位置为起始位置,记录下状态,当数组已遍历完或者遍历到非目标值时,此时上一个位置即为结束位置,时间复杂度为 O ( n ) O(n) O(n),该方法未利用数组有序的条件,典型的二分查找算法,但有一定的变型。
  朴素的二分查找算法,使用传统意义的算法,但当中间值等于目标值时,此时再分别向左和向右扩展,即可找到起始位置和结束位置。此时,最坏情况下的时间复杂度仍然为 O ( n ) O(n) O(n),例如全为目标值组成的数列,如[7,7,7,7,7,7,7],此时仍然要遍历全数组,且还多了二分查找的时间。具体代码实现见Python实现方法一。

(2)改进二分查找算法

  同69. x 的平方根(简单)类似,本质上均属于相同类型的二分查找变型题,在69. x 的平方根(简单)中,寻找算术平方根的整数部分,因此相当于寻找首次大于指定数的整数,该整数减 1 1 1即为所求值,即右指针值。
  针对本题,对于目标值的起始位置和结束位置,可以分别使用二分查找算法寻找。

  • 对于结束位置,寻找最后一个目标值的索引,相当于寻找首次大于目标值的索引,减 1 1 1即可,此时同69. x 的平方根(简单)一致,右指针当中间值大于目标值即会更新为 r i g h t = m i d − 1 right=mid-1 right=mid−1,即 r i g h t right right指针完整的记录下来了最后一个目标值的索引。(满足大于目标值才会更新right的值,因此最终right保留的为最后一次大于目标值的中间值,该中间值即为首次大于目标值的索引,而 r i g h t = m i d − 1 right=mid-1 right=mid−1,即 r i g h t right right指针为结束位置。

  • 对于起始位置,寻找第一个目标值的索引,相当于寻找在目标值出现之前,最后一个不为目标值的索引,加 1 1 1即可,稍微改变下寻找结束位置索引时的寻找条件,因为需要寻找第一个目标值出现前一个位置的索引,那么当中间值大于等于时即更新 r i g h t = m i d − 1 right=mid-1 right=mid−1,此时 r i g h t right right指针完整的记录下来了在目标值出现之前,最后一个不为目标值的索引,此时加 1 1 1即为起始位置的索引。(满足大于等于目标值才会更新 r i g h t right right值 ,故 r i g h t right right记录的是最后一个大于等于目标值的索引,而 r i g h t right right有减1,因此加1即为起始位置。

  • 需要注意的时, r i g h t right right指针记录的不一定是真实的目标值的起始或结束位置的索引,当未找到目标值的时候,程序循环也会结束,因为需要判断找到的起始或者结束位置是否在索引范围内,或者是否目标值,否则返回-1。

  具体代码实现见Python实现方法二。但需要注意的时,此时二分查找起始和结束位置代码冗余度过高,因此可以进一步优化降低代码冗余度,具体代码实现见Python实现方法三。
  Java代码实现直接给出最终优化后算法的实现,见Java实现。

3.代码实现

3.1 Python

  方法一:

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        l, r = -1, -1
        left, right = 0, len(nums) - 1
        while left <= right:
            mid = (left + right) // 2
            if nums[mid] == target:
                l, r = mid, mid
                while l - 1 >= 0 and nums[l-1] == target:
                    l -= 1
                while r + 1 < len(nums) and nums[r+1] == target:
                    r += 1
                break
            elif nums[mid] > target:
                right = mid - 1
            else:
                left = mid + 1
        return [l, r]
        

在这里插入图片描述

  方法二:

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binaeySearchRight(nums, target):
            left, right = 0, len(nums) -1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] > target:
                    right = mid - 1
                else:
                    left = mid + 1
            if right < 0 or nums[right] != target:
                right = -1
            return right
        def binaeySearchLeft(nums, target):
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left +right) // 2
                if nums[mid] >= target:
                    right = mid - 1
                else:
                    left = mid + 1
            right += 1
            if right >= len(nums) or nums[right] != target:
                right = -1
            return right
        left = binaeySearchLeft(nums, target)
        right = binaeySearchRight(nums, target)
        return [left, right]

在这里插入图片描述

  方法三:优化方法二

class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        def binaeySearch(nums, target, direction=True):
            # 规定:True表示查找起始位置,否则查找结束位置
            left, right = 0, len(nums) - 1
            while left <= right:
                mid = (left + right) // 2
                if nums[mid] > target or (direction and nums[mid] >= target):
                    right = mid - 1
                else:
                    left = mid + 1
            if direction:
                right += 1
            if right < 0 or right >= len(nums) or nums[right] != target:
                right = -1
            return right

        left = binaeySearch(nums, target, True)
        right = binaeySearch(nums, target, False)
        return [left, right]

在这里插入图片描述

3.2 Java

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int left = binarySearch(nums, target, true);
        int right = binarySearch(nums, target, false);
        return new int[]{left, right};

    }
    public int binarySearch(int[] nums, int target, boolean direction){
        //规定:True表示查找起始位置,否则查找结束位置
        int left = 0, right = nums.length - 1;
        while (left <= right){
            int mid = (left + right) / 2;
            if (nums[mid] > target || (direction && nums[mid] >= target)){
                right = mid - 1;
            }else{
                left = mid + 1;
            }
        }
        if (direction){right++;}
        if (right < 0 || right >= nums.length || nums[right] != target){right=-1;}
        return right;
    }
}

在这里插入图片描述

  执行用时不必过于纠结,对比可以发现,对于python和java完全相同的编写,java的时间一般是优于python的;至于编写的代码的执行用时击败多少对手,执行用时和网络环境、当前提交代码人数等均有关系,可以尝试完全相同的代码多次执行用时也不是完全相同,只要确保自己代码的算法时间复杂度满足相应要求即可,也可以通过点击分布图查看其它coder的code。

标签:right,target,nums,mid,34,查找,目标值,排序,left
From: https://blog.csdn.net/weixin_38979465/article/details/140104652

相关文章

  • 排序算法(3) 堆排序
    ​堆排序1.算法原理堆排序的原理与部分没听说过该排序方法的同学猜想的不同,它并不是将堆顶元素逐一弹出后压入数组中来得到一个有序的数组。这种方法在初始建堆时需要使用一个数组空间,在得到有序的数组时需要使用另一个数组空间。而堆排序则是在初始数组的基础上直接进......
  • 打卡信奥刷题(251)用Scratch图形化工具信奥P9771[普及组][HUSTFC 2023] 排列排序问题
    [HUSTFC2023]排列排序问题题目描述JokerShaco有一个长度为nnn的排列pp......
  • 快速排序c++&&java代码实现
    快速排序的思想(基于分治法): 每次选一个基准元素x,通过一次遍历将排序表划分为独立的两部分a[l,k-1],a[k+1,r];其中左边的元素<=x,右边的1元素>x,然后递归下去,直到每个块的大小为1;c++#include<bits/stdc++.h>usingnamespacestd;voidquickSort(vector<int>&q,int......
  • 834、基于51单片机的车内换气扇的控制系统(温度,气体,数码管)
    毕设帮助、开题指导、技术解答(有偿)见文末。目录一、设计功能二、proteus仿真三、原理图四、程序源码五、资料包括一、设计功能1、单片机型号:STC89C52/51、AT89C52/51、AT89S52/51等等都可通用。2、车内换气扇的控制系统。3、按键设置阈值,通过数码管显示相关......
  • 树状数组实现 查找逆序对
     题意:输入一个整数n。接下来输入一行n个整数 。1<=  <=n ,且每个数字只会出现一次题解:按每个数字的大小存入树状数组#include<bits/stdc++.h>usingnamespacestd;#definelllonglongconstintN=10000;intarr[N];lla[N];intn;llquery(intx){ll......
  • 【C语言题目】34.猜凶手
    文章目录作业标题作业内容2.解题思路3.具体代码作业标题猜凶手作业内容日本某地发生了一件谋杀案,警察通过排查确定杀人凶手必为4个嫌疑犯的一个。以下为4个嫌疑犯的供词:A说:不是我。B说:是C。C说:是D。D说:C在胡说已知3个人说了真话,1个人说的是假话。现在请......
  • java List集合排序方式
    javaList集合排序方式1.使用直接上代码packagecom.demo;importcn.hutool.core.date.DateTime;importlombok.AllArgsConstructor;importlombok.Data;importjava.util.*;importjava.util.stream.Collectors;publicclassDemoCollectionsSortMain{public......
  • 海思SD3403/SS928V100开发(14)WIFI模块RTL8821驱动调试
    1.前言芯片平台:海思SD3403/SS928V100操作系统平台:Ubuntu20.04.05【自己移植】WIFI模块:LB-LINK的RTL88212. 调试记录参考供应商提供的操作手册2.1lsusb查看设备2.2编译供应商提供的驱动2.2.1修改Makefile2.2.2编译报错解决办法:将Makefile中arm改成ar......
  • 创建数据库时排序规则utf8_general_ci与utf8_bin的区别
    在MySQL数据库中,字符集(如utf8)定义了字符如何存储,而排序规则(Collation)则定义了字符如何比较、排序和区分大小写。utf8_general_ci和utf8_bin是两种常用的UTF-8字符集下的排序规则,它们之间的主要区别如下:utf8_general_ci全称:case-insensitive,意为“不区分大小写”。特点:在比较......
  • 【34. 在排序数组中查找元素的第一个和最后一个位置】
    题目:给你一个按照非递减顺序排列的整数数组nums,和一个目标值target。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值target,返回[-1,-1]。你必须设计并实现时间复杂度为O(logn)的算法解决此问题。示例1:输入:nums=[5,7,7,8,8,10],t......