HOT 100(六)二分查找、栈

一、二分查找

1、搜索插入位置

  • 初始化左右边界:left 指向数组的起始位置,right 指向数组的末尾。
  • 二分查找过程:不断计算中间位置 mid,根据 nums[mid] 与目标值 target 的比较结果,调整 leftright,从而缩小搜索范围。
  • 返回结果:当 left 超过 right 时,搜索结束,返回 left,它是目标值应当插入的位置。
class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            if nums[mid]==target:
                return mid
            elif nums[mid]<target:
                left=mid+1
            else:
                right=mid-1
        return left

2、搜索二维矩阵

①双指针法(前面有)

由题意可得,矩阵的每一行和每一列都按升序排列,因此可以从矩阵的右上角开始,通过逐步排除不符合条件的行或列来缩小查找范围。最终要么找到目标值,要么确定它不存在。

class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        n,m=len(matrix),len(matrix[0])
        i=0;j=m-1
        while i<n and j>=0:
            if matrix[i][j]==target:
                return True
            elif matrix[i][j]>target:
                j-=1
            else:
                i+=1
        return False

②二分法

由于矩阵整体上是有序的,我们可以将二维矩阵视为一个一维有序数组,然后对其进行二分查找。 

索引映射关系:

  • 一维到二维索引
    • 行号:row = index // n,其中 n 是列数。
    • 列号:col = index % n
  • 二维索引到一维索引:index = row * n + col
class Solution:
    def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
        n,m=len(matrix),len(matrix[0])
        left,right=0,n*m-1
        while left<=right:
            mid=(left+right)//2
            if matrix[mid//m][mid%m]==target:
                return True
            elif matrix[mid//m][mid%m]>target:
                right=mid-1
            else:
                left=mid+1
        return False

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

  •  mid=(left+right)//2:这种方式计算的 mid 更偏向于左侧。这是因为当 left+right 为偶数时,它会精确地取中间;而当它为奇数时,mid 会向左侧靠拢。通常用这种方式来查找目标值的第一个位置。

  •  mid=(left+mid+1)//2(偏右):通过在 mid 的基础上加 1,使得在偶数的情况下 mid向右侧靠拢。这通常用于寻找目标值的最后一个位置,因为它倾向于偏向右侧的搜索区域。

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

4、搜索旋转排序数组

题意:

 分两步走:

  • 第一步是找到数组中的旋转点,也就是最小元素的位置(456123中1就是旋转点)。找到旋转点以后,可以修正下面二分查找中mid的值。
  • 第二步是在旋转后的数组中进行二分查找,返回目标值的位置。

详细点说:

步骤 1:找到旋转点(最小元素的位置)
  • 目的:我们需要找到数组中的最小值,这个最小值就是数组旋转的起点。
  • 思路:利用二分查找的思想,如果中间值 nums[mid] 小于或等于右边界值 nums[right],说明最小值在当前中间值的左边或中间值本身;否则,最小值在右边。通过不断缩小搜索范围,最终找到最小值的索引。
步骤 2:在旋转后的数组中查找目标值
  • 目的:在经过旋转的数组中,使用二分查找来找到目标值。
  • 思路:由于数组是经过旋转的,直接对整个数组进行二分查找可能无法得到正确结果。所以我们使用一个技巧,通过旋转点的索引来调整搜索的中间索引,从而在实际旋转后的数组中正确地进行二分查找。
class Solution:
    def search(self, nums: List[int], target: int) -> int:
        if not nums:
            return -1
        left,right=0,len(nums)-1
        while left<right:
            mid=(left+right)//2
            if nums[mid]<=nums[right]:
                right=mid
            else:
                left=mid+1
        pos=left
        left,right=0,len(nums)-1
        while left<=right:
            mid=(left+right)//2
            real_mid=(mid+pos)%len(nums)
            if nums[real_mid]==target:
                return real_mid
            elif nums[real_mid]<target:
                left=mid+1
            else:
                right=mid-1
        return -1

5、搜索旋转排序数组中的最小值

参考4。

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

6、寻找两个正序数组中的中位数

具体思路:

  • 定义两个数组的分割: 假设 nums1nums2 分别有 mn 个元素,分割的意思是把这两个数组分成两部分:

    • 左半部分的元素为:nums1 的前 i 个元素和 nums2 的前 j 个元素。
    • 右半部分的元素为:nums1 的后 m - i 个元素和 nums2 的后 n - j 个元素。
  • 分割后的性质: 为了使得合并后数组的中位数可以通过分割直接得出,我们需要满足以下条件:nums1[i-1] <= nums2[j]nums2[j-1] <= nums1[i],这保证了左半部分所有元素都小于等于右半部分的元素。

  • 通过二分查找确定分割位置: 我们可以在较短的数组 nums1 上使用二分查找来找到合适的 i 值(分割位置),然后 j 的值通过 j = (m + n + 1) // 2 - i 确定。

  • 判断中位数

    • 如果 m + n 是奇数,那么中位数就是左半部分的最大值。
    • 如果 m + n 是偶数,那么中位数是左半部分最大值和右半部分最小值的平均值。
  • class Solution:
        def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
            if len(nums1)>len(nums2):
                nums1,nums2=nums2,nums1
    
            m,n=len(nums1),len(nums2)
            left,right=0,m
            half_len=(m+n+1)//2
    
            while left<=right:
                i=(left+right)//2
                j=half_len-i
    
                if i<m and nums1[i]<nums2[j-1]:
                    left=i+1
                elif i>0 and nums1[i-1]>nums2[j]:
                    right=i-1
                else:
                    max_left=0
                    if i==0:
                        max_left=nums2[j-1]
                    elif j==0:
                        max_left=nums1[i-1]
                    else:
                        max_left=max(nums1[i-1],nums2[j-1])
                    
                    if (m+n)%2==1:
                        return max_left
    
                    min_right=0
                    if i==m:
                        min_right=nums2[j]
                    elif j==n:
                        min_right=nums1[i]
                    else:
                        min_right=min(nums1[i],nums2[j])
                    return (max_left+min_right)/2.0

二、栈

1、有效的括号

  • 初始化栈:使用一个空的 list 作为栈。
  • 遍历字符串:循环遍历字符串中的每个字符。
    1. 如果遇到左括号 ({[,则将相应的右括号 )}] 压入栈中。
    2. 如果遇到右括号,则检查栈是否为空,如果栈为空或者栈顶元素与当前右括号不匹配,返回 False
  • 最终检查:如果遍历完字符串后栈为空,则说明括号匹配成功,返回 True;否则返回 False
class Solution:
    def isValid(self, s: str) -> bool:
        if not s:
            return True
        stk=[]
        for ch in s:
            if ch=='(':
                stk.append(')')
            elif ch=='[':
                stk.append(']')
            elif ch=='{':
                stk.append('}')
            elif not stk or ch!=stk.pop():
                return False
        return not stk

 2、最小栈

class MinStack:

    def __init__(self):
        self.stk=[]

    def push(self, val: int) -> None:
        if not self.stk:
            self.stk.append((val,val))
        else:
            self.stk.append((val,min(val,min(val,self.stk[-1][1]))))

    def pop(self) -> None:
        self.stk.pop()


    def top(self) -> int:
        return self.stk[-1][0]

    def getMin(self) -> int:
        return self.stk[-1][1]



# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()

3、字符串解码

整体思路:

  • 遇到 [ :入栈,存储当前的multi和res。再将res和multi重置,因为进入新的括号后,新的字符串部分需要重新计算重复次数 multi,并且 res 需要开始记录当前括号内的内容。
    • 存储当前的 multi,表示在当前的 [ ] 内的字符串需要重复的次数。例如,在 3[a2[c]] 中,multi 最初是 3,它表明最外层括号内的内容需要重复 3 次。
    • 当前的 res 表示在当前 [ 前已经解码出来的部分字符串。它需要暂时保存起来,等待括号内的字符串解码完成后再拼接回去。例如,3[a2[c]] 中,当我们处理到 [ 时,res 是空的,进入括号后,会处理括号内的部分。),当遇到 [ 时将当前状态保存进栈,遇到 ] 时弹出栈恢复状态。
  • 遇到 ] 出栈:获取上一个保存的 multires。

    • 出栈操作恢复到上一个 [ 前的状态。通过 stack.pop(),我们可以得到上一个 multires,分别是括号之前的字符串以及重复次数。
    • 更新res:res=已经解码部分字符串+当前括号内字符串重复次数*当前括号内字符串
  • 遇到字符:与前面进行拼接。
class Solution:
    def decodeString(self, s: str) -> str:
        stk=[]
        res=""
        multi=0
        for ch in s:
            if ch=='[':
                stk.append((multi,res))
                res,multi="",0
            elif ch==']':
                cur_multi,last_res=stk.pop()
                res=last_res+cur_multi*res
            elif '0'<=ch<='9':
                multi=multi*10+int(ch)
            else:
                res+=ch
        return res

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/872877.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Lenze伦茨E82ZBC, E82ZBB E82ZMBRB安装说明手测

Lenze伦茨E82ZBC, E82ZBB E82ZMBRB安装说明手测

VMware17 虚拟机下载以及 CentOS8 操作系统安装配置 一条龙全教程

目录 一、安装 vmware workstation 虚拟机 二、安装 CentOS8 操作系统 三、安装 FinalShell 远程连接 一、安装 vmware workstation 虚拟机 安装中...&#xff08;耐心等待&#xff09; 到此安装完成&#xff0c;点击启动运行 激活码如下&#xff1a; MC60H-DWHD5-H80U…

【个人笔记】VCS工具与命令

Title&#xff1a;VCS工具学习 一 介绍 是什么&#xff1f; VCS (Verilog Compiler Simulator) 是synopsys的verilog 仿真软件&#xff0c;竞品有Mentor公司的Modelsim、Cadence公司的NC-Verilog、Verilog—XL. VCS能够 分析、编译 HDL的design code&#xff0c;同时内置了 仿…

API 网关 OpenID Connect 实战:单点登录(SSO)如此简单

作者&#xff1a;戴靖泽&#xff0c;阿里云 API 网关研发&#xff0c;Higress 开源社区 Member 前言 随着企业的发展&#xff0c;所使用的系统数量逐渐增多&#xff0c;用户在使用不同系统时需要频繁登录&#xff0c;导致用户体验较差。单点登录&#xff08;Single Sign-On&a…

Python和MATLAB(Java)及Arduino和Raspberry Pi(树莓派)点扩展函数导图

&#x1f3af;要点 反卷积显微镜图像算法微珠图像获取显微镜分辨率基于像素、小形状、高斯混合等全视野建模基于探测器像素经验建模荧光成像算法模型傅里叶方法计算矢量点扩展函数模型天文空间成像重建二维高斯拟合天体图像伽马射线能量和视场中心偏移角标量矢量模型盲解卷积和…

每日OJ_牛客_求和(递归深搜)

目录 牛客_求和&#xff08;递归深搜&#xff09; 解析代码 牛客_求和&#xff08;递归深搜&#xff09; 求和_好未来笔试题_牛客网 解析代码 递归中每次累加一个新的数&#xff0c;如果累加和大于等于目标&#xff0c;结束递归。此时如果累加和正好等于目标&#xff0c;则打…

Quartz.Net_快速开始

简述 Quartz中主要分为三部分&#xff0c;JobDetail、Trigger、Scheduler&#xff0c;分别是任务、触发器、调度器&#xff0c;三者的关系为&#xff1a;Trigger控制JobDetail的执行时间和频率&#xff0c;而Scheduler负责将具体的Trigger与具体的JobDetail绑定 1.安装Quartz…

【无线通信发展史⑧】测量地球质量?重力加速度g的测量?如何推导单摆周期公式?地球半径R是怎么测量出来的?

前言&#xff1a;用这几个问答形式来解读下我这个系列的来龙去脉。如果大家觉得本篇文章不水的话希望帮忙点赞收藏加关注&#xff0c;你们的鼓舞是我继续更新的动力。 我为什么会写这个系列呢&#xff1f; 首先肯定是因为我本身就是一名从业通信者&#xff0c;想着更加了解自…

十大口碑最好开放式蓝牙耳机是哪些?五款热销好用产品测评!

​开放式耳机现在超火&#xff0c;成了时尚、好看又舒服的代名词&#xff0c;迅速俘获了一大波粉丝&#xff0c;成了耳机界的新宠儿。跟那些传统的入耳式耳机比起来&#xff0c;开放式耳机戴着更稳&#xff0c;对耳朵也更友好。不过&#xff0c;也有人觉得这玩意儿不值&#xf…

vue3集成sql语句编辑器

使用的是codemirror 安装 pnpm add codemirror vue-codemirror --savepnpm add codemirror/lang-sqlpnpm add codemirror/theme-one-dark使用 <template><codemirror v-model"configSql" placeholder"Code goes here..." ref"codemirrorR…

AIGC与数据分析融合,引领商业智能新变革(TOP企业实践)

AIGC与数据分析融合&#xff0c;引领商业智能新变革&#xff08;TOP企业实践&#xff09; 前言AIGC与数据分析融合 前言 在当今数字化时代&#xff0c;数据已成为企业发展的核心资产&#xff0c;而如何从海量数据中挖掘出有价值的信息&#xff0c;成为了企业面临的重要挑战。随…

云服务器内网穿透连接云手机配置ALAS

文章目录 服务器安装TailscaleNAT网络&#xff08;无独立IP&#xff09;云服务器安装Tailscale有固定IP的云服务器安装Tailscale 云手机安装Tailscale开启无线网络调试安装Tailscale ALAS连接云手机 上次写到服务器连接云手机时只说了有独立IP的&#xff0c;但有独立IP的云手机…

算法打卡——田忌赛马问题

问题简介&#xff1a;就是一个贪心的思想&#xff0c;下面上题目 要求示例输出输入 大体上先比较快马&#xff0c;田的快马与王的快马 其次比较田的慢马与王的慢马&#xff0c; 两处边界比较完全之后可以直接贪心了 几份示例的代码 代码一 #include <bits/stdc.h> …

个人旅游网(3)——功能详解——旅游路线功能

文章目录 一、旅游路线分类功能1.1、接口详解1.1.1、findAll 二、路线分类下的旅游路线功能2.2、接口详解2.2.1、findRouteListByCid 三、点击单条旅游路线查看其详情功能3.1、接口详解3.1.1、findRouteListByRid 四、分页功能4.1、导入依赖4.2、配置项的配置4.3、实现分页 一、…

每日一题~cf 970 div3 (A思维,B小模拟,C二分,D排列数建图成环,E 26个字母暴力+前缀和,F 逆元,G 数论gcd )

A 题意&#xff1a; 有 a 个1 ,b 个2.问是否能将这些数划分为两个数值相等的集合。 输出 YES 或者 NO —————— 问题等价于 将数组 分成两个数值相同的数组。所以sum 应该是偶数。也就是说 1 的个数是偶数。在i1的个数是偶数的情况下&#xff0c;将 2 分成两份&#xff0c;…

使用 EMQX 开源版的 Webhook 机制处理消息并存储数据

1、前言 EMQX 是一款强大的开源 MQTT 消息代理&#xff0c;它支持大量的连接和高吞吐量&#xff0c;适用于各种物联网应用。Webhook 是 EMQX 提供的扩展功能之一&#xff0c;用于将消息推送到外部的 HTTP 服务。在本文中&#xff0c;我们将介绍如何使用 EMQX 开源版的 Webhook …

整型数组按个位值排序

题目描述 给定一个非空数组(列表)&#xff0c;其元素数据类型为整型&#xff0c;请按照数组元素十进制最低位从小到大进行排序&#xff0c;十进制最低位相同的元司 相对位置保持不变。 当数组元素为负值时&#xff0c;十进制最低位等同于去除符号位后对应十进制值最低位。 输…

QT核心内容(9.6)

1> 手写unique_ptr智能指针 代码&#xff1a; #include <iostream> #include <cassert>using namespace std; template<typename T> class my_unique_ptr { private:T* ptr;// 禁止拷贝构造函数和拷贝赋值操作符my_unique_ptr(const my_unique_ptr&a…

手机扬声器音量总是不够大?试试“扬声器助推器”吧

手机的扬声器音量总是不够大&#xff0c;尤其是在嘈杂的环境中&#xff0c;音乐和视频的声音总是不太清晰。直到我发现了这款“扬声器助推器”&#xff0c;我的手机音质瞬间提升了好几个档次。 软件简介&#xff1a; “扬声器助推器”利用先进的音频处理技术&#xff0c;能够…

vivado error:Combinatorial Loop Alert:1 LUT cells form a combinatorial loop

VIVADO ERROR :Combinatorial Loop Alert&#xff1a;1 LUT cells form a combinatorial loop vivao生成bit流时发生报错&#xff0c;如下图所示定位原因解决 vivao生成bit流时发生报错&#xff0c;如下图所示 定位原因 在三段式状态机中&#xff0c;组合逻辑代码if else 语句…