双指针问题的算法

双指针主要分两类: 快慢指针和左右指针

对于 链表问题, 我们一般可以使用 快慢指针解决
所谓的快慢指针是指, 使用两个指针按照不同的速度前进, 有两个指针我们可以确定:

一些题目

注意: 两个指针相遇则有环 (类比在操场跑步, 速度不相等总能相遇)

class Solution:
    def hasCycle(self, head: Optional[ListNode]) -> bool:
        if not head:
            return False
        fast_node = head.next
        slow_node = head
        while fast_node and fast_node.next:
            if slow_node == fast_node:
                return True
            fast_node = fast_node.next.next
            slow_node = slow_node.next
        return False

又比如:

左右指针一般的形式就是我们常说的 二分查找(二分搜索)

一般的使用方式:

def binary_search(nums: List[int], target: int):
    left = 0
    right = ...

    while ...:
        mid = left + (right - left) / 2
        if nums[mid] == target:
            ...

        elif nums[mid] < target:
            left = ...

        elif nums[mid] > target:
            right = ...

    return ...

我们需要的注意点为 ...部分:

对于一些问题, 我们可以将问题的区间统一为 [left : right], 即 right = len(nums) - 1while left <= right< code><!--=-->

比如:
返回某个值的问题

def binary_search(nums: List[int], target: int):
    left = 0
    right = len(nums) - 1
    while left  target:
            right = mid - 1
        elif nums[mid] == target:
            # 直接返回
            return mid
    return -1

返回左边界的问题

def left_bound(nums: List[int], target: int):
    left = 0
    right = len(nums) - 1
    while left  target:
            right = mid - 1
        elif nums[mid] == target:
            # 别返回,锁定左侧边界
            right = mid - 1

    # 最后要检查 left 越界的情况
    # left可能超出范围 即 >= len(nums)
    if left >= len(nums) or nums[left] != target:
        return -1
    return left

结束条件为: [right + 1 : right](如: [3 : 2])
返回左边界 left

返回右边界的问题

def right_bound(nums: List[int], target: int):
    left = 0
    right = len(nums) - 1
    while left  target:
            right = mid - 1
        elif nums[mid] == target:
            # 别返回,锁定右侧边界
            left = mid + 1

    # 最后要检查 right 越界的情况
    if right < 0 or nums[right] != target:
        return -1

    return right

结束条件为: [right + 1 : right](如: [3 : 2])
返回右边界 right

在leetcode上对应的题目:

滑动窗口是双指针的一种, 也可以说是左右指针的一种
其主要解决的是 子串问题
所谓的子串问题是指: 一个长的字符串是否全部包含 一个短的字符串 (包括数量)
滑动窗口的思想:
① 我们可以设两个指针, 分别对应窗口的左右边界
② 右边界向右扩大窗口, 直到找到符合条件的子串
③ 左边界向右缩小窗口, 更新数据, 根据题目是否返回
④ 假如还未返回, 则重复②和③
⑤ 根据题目是否返回

模板:

def sliding_window(s: str, t: str):
"""
    :param s 大的字符串
    :param t 小的字符串
    :return 根据题目返回

"""
    need = {}  # 存放需要的字符数
    windows = {}  # 存放当前窗口中的字符数
    # 记录需要的字符数
    for char in t:
        # 需要字符的数量自增1
        need[char] = need.setdefault(char, 0) + 1  # setdefault作用字典中不存在字符时, 返回0
    # 左右边界的指针
    left = right = 0
    # 用于记录已经通过检验的字符数
    valid = 0
"""
    假如有其他变量可以在这里添加
"""
    while right < len(s):
        # right_char为将要移入的窗口字符
        right_char = s[right]
        # 右移窗口
        right += 1
        # 假如当前 右边界 的字符,为需要的字符
        if right_char in need:
"""
            更新数据
            一般是
            1. 当前窗口的数据
            2. 通过的 字符数
"""
            # 记录当前窗口符合要求的字符数量
            windows[right_char] = windows.setdefault(right_char, 0) + 1
            # 假如当前字符已经符合要求
            # 通过检验的字符数 + 1
            if windows[right_char] == need[right_char]:
                valid += 1

        # 判断左边界是否可以收缩
        # !!!! 这个条件根据题目而变
        while condition:
"""
            根据题目是否在这里返回
"""

            # left_char为将要移出的窗口字符
            left_char = s[left]
            left += 1
            if left_char in need:
""""
                更新数据
                一般是
                1. 当前窗口的数据
                2. 通过的 字符数

                自定义的其他变量也在这里更新
"""
                # 假如当前字符已经符合要求
                # 通过检验的字符数 - 1
                if windows[left_char] == need[left_char]:
                    valid -= 1
                # 记录当前窗口符合要求的字符数量 - 1
                windows[left_char] = windows.setdefault(left_char, 0) - 1
"""
    根据题目是否在这里返回
"""

这个模板的主要注意点是

一些题目

Original: https://www.cnblogs.com/lczmx/p/15859259.html
Author: 403·Forbidden
Title: 双指针问题的算法

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/581327/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • spring boot、spring cloud、spring cloud alibaba、nacos之间的版本对应

    1、刚开始,我的spring cloud alibaba的版本为2.1.0,nacos版本为1.4.1 然后报错如下: 说明没有读取到nacos中的配置,nacos中的配置如下: …

    Java 2023年5月30日
    073
  • Linux常用指令

    Linux常用指令 文件目录类 linux系统文件目录结构 当前工作目录的绝对路径(pwd 指令) 基本语法 pwd 功能描述:显示当前工作目录的绝对路径 显示文件或目录(ls 指…

    Java 2023年6月5日
    074
  • Java并发工具类

    在 JDK5 之后的并发包中提供的 CountDownLatch 也可以实现 join 的功能,并且比 join 的功能更多 2.CyclicBarrier CyclicBarri…

    Java 2023年5月29日
    096
  • validform学习

    1 说明 validform非常实用,可以用来进行表单验证,是基于jquery框架的,一共就导出两个文件,一个css文件,一个js文件。启动也只需一句js语句即可,相当方便。 可以…

    Java 2023年6月7日
    054
  • pycharm可以运行但无法debug的解决方法

    错误信息:pydev debugger: process 4588 is connecting 如果您尝试了网上的很多方法如防火墙设置,去掉 “.idea”…

    Java 2023年6月9日
    094
  • java内存区域模型和详解

    一,概述 java虚拟机运行时数据区模型图: 主要包括:程序计数器,java虚拟机栈,本地方法栈,java 堆,方法区(元空间)。 其中堆和方法区由所有线程共享的数据区;程序计数器…

    Java 2023年6月13日
    070
  • Java并发编程:4种线程池和缓冲队列BlockingQueue

    一. 线程池简介 线程池的概念: 线程池就是首先创建一些线程,它们的集合称为线程池。使用线程池可以很好地提高性能,线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,…

    Java 2023年5月29日
    070
  • 数据结构–稀疏数组和队列

    最近在学尚硅谷的数据结构,特此开一篇blog来做笔记 当一个数组中大部分元素是0时,或者为同一个值的数组时,可以用稀疏数组来保存该数组,节省储存空间(二维数组储存太浪费空间了) 应…

    Java 2023年6月8日
    0116
  • JUnit 单元测试方法中启用子线程的问题

    其实junit是将test作为参数传递给了TestRunner的main函数。并通过main函数进行执行。 test函数在main中执行。如果test执行结束,那么main将会调用…

    Java 2023年5月29日
    093
  • Java: native

    解释 native主要用于 方法上 1、一个native方法就是一个Java调用非Java代码的接口。一个native方法是指该方法的实现由非Java语言实现,比如用C或C++实现…

    Java 2023年6月7日
    094
  • MongoDB 学习笔记

    概述 MongoDB 是一个介于关系型数据库和非关系型数据库之间的产品,是非关系型数据库中功能最丰富,最像关系型数据库的。 MongoDB 支持的数据结构非常松散,类似 json …

    Java 2023年6月8日
    0178
  • 部署-jenkins发布项目到windows环境

    使用openSSH的方式 如果我们项目的部署环境在windows环境上,我们可以选择给服务器安装openSSH的方式,然后以脚本的方式进行部署。也可以通过web容器的对外访问地址,…

    Java 2023年6月7日
    082
  • spring boot 集成 Swagger 接口文档

    1.添加依赖 2.在 Spring Boot 配置文件中添加配置参数 3.创建配置类: Swagger 默认会根据配置的包,扫描所有接口并生成对应的 API 描述和参数信息,但这样…

    Java 2023年5月30日
    072
  • 好家伙,分布式配置中心这种组件真的是神器

    我是3y,一年 CRUD经验用十年的 markdown程序员👨🏻‍💻常年被誉为优质八股文选手 上次给大家安排了 监控的相关使用姿势,不知道大家有没有配置起来。但我可不管你们的进度怎…

    Java 2023年6月9日
    094
  • Java学习-087-自定义MANIFEST.MF 文件并打包生效

    在 src/main/resources 文件夹下创建 MANIFEST.MF 文件,文件内容如下所示: Created-By: 范丰平 Manifest-Version: 1.0…

    Java 2023年5月29日
    087
  • Linux自动安装jdk脚本分享,亲测好用

    最近在工作中需要频繁的安装模板服务器,安装这些繁琐的基础环境,所以写了一个自动安装的脚本来增工作效率: 使用方法: sh 脚本名字.sh 需要安装jdk的压缩包名字 即可安装 最后…

    Java 2023年6月16日
    087
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球