LeetCode - 双指针(Two Pointers) 算法集合 [对撞指针、快慢指针、滑动窗口、双链遍历]

news2024/11/18 17:36:23

欢迎关注我的CSDN:https://spike.blog.csdn.net/
本文地址:https://spike.blog.csdn.net/article/details/139270999

Two Sum

双指针算法是一种常见且灵活的技巧,通过使用两个指针协同完成任务。这些指针可以指向不同的元素,具体应用取决于问题的性质。双指针算法的常见用法:

  1. 对撞指针:一左一右向中间逼近。例如,反转字符串中的元音字母问题,可以使用对撞指针。
  2. 快慢指针:一快一慢,步长不同。例如,判断链表中是否有环问题,可以使用快慢指针,看慢指针是否能追上快指针。单链表找中间节点问题也可以用快慢指针,快指针到链表结尾,慢指针到一半。
  3. 滑动窗口:类似计算机网络中的滑动窗口。一般是右端向右扩充,达到停止条件后右端不动,左端向右端逼近,逼近达到停止条件后,左端不动,右端继续扩充。

双指针算法包括:对撞指针快慢指针滑动窗口双链遍历

  1. 167. 两数之和 II - 输入有序数组 - 对撞指针
  2. 633. 平方数之和 - 对撞指针,题目167变种
  3. 680. 验证回文串 II - 对撞指针,需要判断去除1个字符 l+1 或 r-1
  4. 15. 三数之和 - 两数之和的进阶版,先排序,逐步修改序列
  5. 142. 环形链表 II - 快慢指针
  6. 76. 最小覆盖子串 - 滑动窗口,Counter类的使用
  7. 88. 合并两个有序数组 - 双链遍历
  8. 524. 通过删除字母匹配到字典里最长单词 - 双链遍历,优先排序,再依次比较。

1. 对撞指针

167. 两数之和 II - 输入有序数组 - 对撞指针

class Solution:
    def twoSum(self, numbers: List[int], target: int) -> List[int]:
        """
        时间复杂度O(n),空间复杂度O(1)
        """
        # 输入的已经排序
        n=len(numbers)  # 数量
        l,r=0,n-1  # 左右指针
        while l<r:
            v=numbers[l]+numbers[r]  # 两数之和
            if v>target: # 移动指针
                r-=1
            elif v<target:
                l+=1
            else:
                return [l+1,r+1]

633. 平方数之和 - 对撞指针,167变种

class Solution:
    def judgeSquareSum(self, c: int) -> bool:
        """
        时间复杂度 O(n),空间复杂度 O(1)
        """
        # 左右指针
        l, r = 0, int(sqrt(c))
        while l <= r:  # 遍历条件需要相等
            # 计算值
            v = pow(l, 2) + pow(r, 2)
            if v > c:  # 移动右指针
                r -= 1
            elif v < c:  # 移动左指针
                l += 1
            else:
                return True
        return False

680. 验证回文串 II - 对撞指针,需要判断去除1个字符 l+1 或 r-1

class Solution:
    def validPalindrome(self, s: str) -> bool:
        """
        时间复杂度 O(n), 空间复杂度 O(1)
        """
        def check(l, r):
            """
            检查s是否是回文
            """
            while l < r:
                if s[l] == s[r]:
                    l += 1
                    r -= 1
                else:
                    return False
            return True
        n = len(s)
        l, r = 0, n-1  # 左右指针
        while l < r:
            if s[l] == s[r]:  # 回文
                l += 1
                r -= 1
            else:
                # 越过1个值,最多可以从中删除一个字符
                return check(l+1, r) or check(l, r-1)
        return True

15. 三数之和 - 两数之和的进阶版,先排序,逐步修改序列

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        """
        时间O(N^2),空间O(logN) -> 排序
        """
        def two_sum(nums, t):
            """
            经典的两数之和,同时,避免重复添加
            """
            n = len(nums)
            l, r = 0, n-1
            res = []
            while l < r:
                x = nums[l] + nums[r]
                if x > t:
                    r -= 1
                elif x < t:
                    l += 1
                else:
                    sr = [nums[l], nums[r], -t]
                    if sr not in res:  # 避免重复添加
                        res.append(sr)
                    l += 1
            return res
        
        nums.sort()  # 排序
        n = len(nums)  # 序列长度
        res = []  # 输出结果
        for i in range(n):
            # 避免重复数字
            if i > 0 and nums[i-1] == nums[i]:
                continue
            t = nums[i]  # 依次遍历
            res += two_sum(nums[i+1:], -t)
        
        return res

2. 快慢指针

142. 环形链表 II - 快慢指针

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]:
        """
        时间复杂度O(n),空间复杂度O(1)
        """
        if not head:
            return None
        # 快慢指针先指向head
        slow=fast=head
        # 判断是否运行到结尾
        while fast.next and fast.next.next:
            slow=slow.next  # 移动1步
            fast=fast.next.next  # 移动2步
            if slow==fast:
                fast=head # fast从head开始重新计数
                while slow!=fast:  # 移动到位置
                    slow=slow.next
                    fast=fast.next
                return fast # 相等即返回
        return None

3. 滑动窗口

76. 最小覆盖子串 - 滑动窗口

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        """
        时间复杂度 O(m+n),空间复杂度 O(1)
        """
        rl,rr=-1,len(s) # 目标的最大窗口
        l=0  # 左指针
        cnt_s=Counter()  # 计数器字典
        cnt_t=Counter(t) # 目标计数器字典
        less=len(cnt_t)  # 不重复的t字母数量
        for r,c in enumerate(s):
            cnt_s[c]+=1  # s计数器
            if cnt_s[c]==cnt_t[c]:  # 数量相等
                less-=1  # 数量减一
            while less==0:  # 满足条件
                if r-l < rr-rl:  # 区间更小
                    rl,rr=l,r  # 更新左右指针
                # -----
                # 如果数量相等,之后数量需要减一,所以less需要提前+1
                x=s[l]  # 左指针当前字母
                if cnt_s[x]==cnt_t[x]:  
                    less+=1  # 不重复+1
                cnt_s[x]-=1  # 指针减1
                l+=1  # 已经更新,所以需要移动左指针
                # -----
        return "" if rl<0 else s[rl:rr+1]

4. 双链遍历

88. 合并两个有序数组 - 双链指针

class Solution:
    def merge(self, nums1: List[int], m: int, nums2: List[int], n: int) -> None:
        """
        Do not return anything, modify nums1 in-place instead.
        时间复杂度 O(n),空间复杂度 O(1)
        """
        pos=(m-1)+(n-1)+1  # 最远位置
        m-=1  # 最后位置
        n-=1  # 最后位置
        while m>=0 and n>=0:  # 遍历两个数组
            # 注意: 大于等于确保,优先移动m
            if nums1[m]>=nums2[n]:
                nums1[pos]=nums1[m]  # 赋值大值
                m-=1
            else:
                nums1[pos]=nums2[n]
                n-=1
            pos-=1  # 移动指针
        while n>=0: # 优先移动m,所以剩下的就是n
            nums1[pos]=nums2[n]
            pos-=1
            n-=1

524. 通过删除字母匹配到字典里最长单词 - 双链指针,优先排序,再依次比较。

class Solution:
    def findLongestWord(self, s: str, dictionary: List[str]) -> str:
        """
        d 是字典长度,m 是s长度
        时间复杂度 O(d x (m+n)),空间复杂度 O(d x m)
        """
        # 按目标结果排序,优先做前面的
        words = sorted(dictionary, key=lambda x: (-len(x), x))
        for t in words:
            i = j = 0  # 双指针
            while i < len(t) and j < len(s): # 双指针遍历
                if t[i] == s[j]:  # 相同
                    i += 1  # t指针+1,满足条件
                j+=1  # s指针默认都+1
                if i == len(t):  # 长度满足
                    return t  # 直接返回
        return ""

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何将红酒配餐融入日常生活

红酒配餐不仅可以提升用餐的品质&#xff0c;还可以为日常生活增添一份优雅和情调。云仓酒庄雷盛红酒以其卓着的品质和丰富的口感&#xff0c;成为了实现红酒配餐融入日常生活的理想选择。下面将介绍如何将雷盛红酒配餐融入日常生活。 首先&#xff0c;了解红酒的基本知识。了解…

动态规划part01 Day41

动态规划算法解题步骤 确定dp数组&#xff08;dp table&#xff09;以及下标的含义确定递推公式dp数组如何初始化确定遍历顺序举例推导dp数组 LC509斐波那契数 LC70爬楼梯 LC746使用最小花费爬楼梯 dp[]含义&#xff1a;爬到第i层楼梯的最小花费

webpack5基础和开发模式配置

运行环境 nodejs16 webpack基础 webpack打包输出的文件是bundle 打包就是编译组合 webpack本身功能 仅能编译js文件 开始使用 基本配置 五大核心概念 准备webpack配置文件 1.在根目录 2.命名为webpack.config.js 开发模式介绍 处理样式资源 处理css样式资源文件…

攻防世界-bug题目详解

1.打开靶场&#xff0c;先注册一个用户&#xff0c;然后登录上&#xff0c;注册的时候发现用户名为admin的用户存在&#xff0c;于是注册的用户为admin123123 点击personal如图所示可以知道我注册的这个用户的uid是5&#xff0c;然后还有我注册时候的信息 使用burp抓包&#…

零基础小白本地部署大疆上云api(个人记录供参考)

文章目录 运行前准备前后端项目运行1.前端项目&#xff1a; 后端项目运行必须先依靠emqx运行必须先依靠redis运行修改后端项目的application.yml文件 运行前准备 1.保证电脑又node.js环境&#xff0c;可以正常使用npm 2.Java的jdk必须是11及以上版本否则无效 3.下载好emqx,red…

three.js 性能对比 babylon.js

babylon.js pbr 材质, 27帧 three.js pbr 材质, 26 帧 6172 个mesh.

小阿轩yx-Shell 编程之循环语句与函数

小阿轩yx-Shell 编程之循环语句与函数 for 循环语句 可以很好地解决顺序编写异常烦琐、困难重重的全部代码 &#xff08;&#xff09;{}&#xff1a;里边写的都是命令 &#xff09;&#xff1a;不能嵌套 $&#xff08;&#xff09;&#xff1a;可以嵌套&#xff0c;适合更…

使用Datav,echarts开发各种地图

一、功能描述 在实际中&#xff0c;有时候需要针对不同的地图进行开发&#xff0c;而能在网上找到现成&#xff0c;与需要匹配度高的&#xff0c;几乎很难&#xff0c;而且找起对应的资源也相对麻烦。所以结合DataV提供的地图数据&#xff0c;就能开发出各种地图&#xff0c;然…

机器学习-3-特征工程的重要性及常用特征选择方法

参考特征重要性:理解机器学习模型预测中的关键因素 参考[数据分析]特征选择的方法 1 特征重要性 特征重要性帮助我们理解哪些特征或变量对模型预测的影响最大。 特征重要性是数据科学中一个至关重要的概念,尤其是在建立预测性任务的模型时。想象你正在尝试预测明天是否会下…

2024年电子、电气与信息科学国际会议(EEIS 2024)

2024年电子、电气与信息科学国际会议&#xff08;EEIS 2024&#xff09; 2024 International Conference on Electronics, Electrical and Information Science 【重要信息】 大会地点&#xff1a;昆明 大会官网&#xff1a;http://www.iceeis.com 投稿邮箱&#xff1a;iceeis…

为什么要学习c++?

你可能在想&#xff0c;“C&#xff1f;那不是上个时代的产物吗&#xff1f;” 哎呀&#xff0c;可别小看了这位“老将”&#xff0c;它在21世纪的科技舞台上依旧光芒万丈&#xff0c;是许多尖端技术不可或缺的基石&#xff01; 1. 无可替代 c源于c语言&#xff0c;它贴近于硬…

5月28(信息差)

&#x1f30d; 胖东来“改造”永辉超市 细则公布 胖东来“改造”永辉超市 细则公布&#xff01; &#x1f384;在 Windows 下玩转多媒体处理框架 BMF https://juejin.cn/post/7371640570421755913 ✨四川&#xff1a;将人工智能作为一号创新工程&#xff0c;加快突破一批原…

提高联盟营销收入的秘密武器

联盟营销已经成为推广产品和服务的关键策略之一。通过利用社交媒体平台如Facebook、X&#xff08;前Twitter&#xff09;、Instagram和TikTok&#xff0c;联盟客能够触及广泛的潜在客户&#xff0c;展开高效的营销活动。 如今&#xff0c;联盟客手握多个账号来拓展自己的业务已…

SQL实战 将学生信息进行 行转列输出

表countries 数据如下&#xff1a; namecontinentJaneAmericaPascalEuropeXiAsiaJackAmerica数据建表来源&#xff1a; SQL试题使得每个学生 按照姓名的字⺟顺序依次排列 在对应的⼤洲下⾯展示为如下的数据样式&#xff1a; namecontinentJane, JackAmericaXiAsiaPascalPasca…

Vue 3指令与事件处理

title: Vue 3指令与事件处理 date: 2024/5/25 18:53:37 updated: 2024/5/25 18:53:37 categories: 前端开发 tags: Vue3基础指令详解事件处理高级事件实战案例最佳实践性能优化 第1章 Vue 3基础 1.1 Vue 3简介 Vue 3 是一个由尤雨溪&#xff08;尤大&#xff09;领导的开源…

airtest做web端UI自动化实战

安装 官网下载客户端 airtest库安装 pip install airtest pip install pocoui脚本录制 利用airtest客户端录制脚本 web端辅助插件-selenium windows打开: 设置chrome路径 开始调式录制 脚本运行 # -*- coding: utf-8 -*- """ Time &#xff1a; 2024/5/…

安装mysql的MGR集群

说明 1、 mysql数据库主从宕机&#xff0c;会影响到正常业务访问&#xff0c;并且要手动进行切换。 2、 MHA高可用搭建复杂&#xff0c;代码已停止更新。 3、 MGR集群搭建方便&#xff0c; master故障会自动进行切换&#xff0c;不影响业务正常访问。 一、环境准备 1、主机说明…

安全测试跟自动化测试,哪个方向发展好一些?

引言&#xff1a; 在当今高度互联的数字化时代&#xff0c;软件的安全性和质量成为企业和用户关注的焦点。安全测试和自动化测试作为软件测试领域的两个重要分支&#xff0c;为确保软件系统的稳定性和可靠性发挥着重要作用。本文将深入探讨安全测试和自动化测试的发展方向&…

shell中编写备份数据库脚本(使用mysqldump工具)

mysqldump备份 目录 mysqldump备份 分库备份 分表备份 利用自带工具mysqldump 实现数据库分库分表备份。 要想知道需要备份哪些数据库&#xff0c;就得先列出来 mysql -uroot -pOpenlab123! -N -e show databases | egrep -on_schema|mysql|performance_schema|sys" …

使用BigDecimal定义的实体类字段返回给前台的是字符串类型,如何返回数字类型

目录 前言&#xff1a; 问题现象&#xff1a; 解决方法&#xff1a; 效果&#xff1a; 前言&#xff1a; 做项目的时候数据字段通常定义为bigdecimal类型&#xff0c;方便进行运算&#xff0c;但是发现接口调用后返回给前台的是字符串&#xff0c;这篇博文讲的是如何将定义…