【chap6-字符串】用Python3刷《代码随想录》

news2024/9/21 16:48:10

字符串是由若干字符组成的有限序列,也可以理解为一个字符数组


344. 反转字符串 

344. 反转字符串

思路:双指针法。定义两个指针(即索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素

  • 反转链表和反转字符串都是双指针法,但字符串也是一种数组,故元素在内存中是连续分布的(跟链表不同)
class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        i, j = 0, len(s)-1
        for i in range(len(s)):
            if i < j:
                s[i], s[j] = s[j], s[i]
                i += 1
                j -= 1
        return s

541. 反转字符串II 

541. 反转字符串 II

题意简单概括:对于字符串s,每次遍历其2k的长度,反转2k长度里的前k个;若最后一组的长度不足2k但大于k,只反转这k个;若不足k,全部反转

首先,这题可以调用 344题反转字符串 中的函数,但要注意的是,344题的输入是一个字符组成的列表,而这题是字符串

  • 对字符串str 转 字符列表 list,用 list() 即可
  • 字符列表res 拼接回 字符串,用 "".join(res)

其次,分析本题哪些部分需要反转。注意,对于字符串s,是2k个长度去遍历的。对于2k个长度中的前k个进行反转 

  1. 使用 range(start, end, step) 来确定需要调换的初始位置 
  2. 对于字符串s = 'abc',如果使用s[0:999] ===> 'abc'。字符串末尾如果超过最大长度,则会返回至字符串最后一个值,这个特性可以避免一些边界条件的处理
  3. 用切片整体替换,而不是一个个替换
class Solution:
    def reverseStr(self, s: str, k: int) -> str:
        # 先定义一个反转函数
        def reverse(s):   # List[str]
            i, j = 0, len(s)-1
            for i in range(len(s)):
                if i < j:
                    s[i], s[j] = s[j], s[i]
                    i += 1
                    j -= 1
            return s

        res = list(s)   # str —> list
        for i in range(0, len(s), 2*k):  # 每次跳2k步
            res[i: i+k] = reverse(res[i: i+k])   # 切片是左闭右开
        return ''.join(res)


剑指offer 05. 替换空格

剑指 Offer 05. 替换空格

因为Python中字符串是不可变类型,所以操作字符串需要将其转换为列表,因此空间复杂度不可能为O(1)

法1:比较直观的一种方法。添加空列表,添加匹配的结果

class Solution:
    def replaceSpace(self, s: str) -> str:
        res = []
        for i in range(len(s)):
            if s[i] != ' ':   # 注意引号中间要打一个空格
                res.append(s[i])
            else:
                res.append('%20')
        return "".join(res)

法2:双指针。首先扩充数组到每个空格替换成 %20 之后的大小,然后从后向前替换空格(为什么是从后向前?因为从前向后填充的话,每次添加元素都要将添加元素之后的所有元素向后移动)

很多数组填充类的问题,都可以预先给数组扩容成填充后的大小,然后再从后向前进行操作

class Solution:
    def replaceSpace(self, s: str) -> str:
        cnt = s.count(' ')   # 统计字符串s里有多少个空格
        res = list(s)   # str —> list
        res.extend([' ']*2*cnt)  # 每个空格都要换成%20,长度+2
        
        # left遍历s,若遇到空格,则替换为%20;否则直接赋给right
        left, right = len(s)-1, len(res)-1   # 从后向前遍历
        while left >= 0:
            if res[left] != ' ':
                res[right] = res[left]
                right -= 1
            else:
                res[right-2: right+1] = '%20'   # 左闭右开 [right-2, right)
                right -= 3
            left -= 1
        return "".join(res)

151. 反转字符串中的单词 

151. 反转字符串中的单词

思路:移除多余空格(双指针法) —> 将整个字符串反转 —> 将每个单词反转(先整体反转再局部反转)

class Solution:
    def reverseWords(self, s: str) -> str:
        s = s.strip()   # 先去除字符串前后的空格
        s = s[::-1]   # 反转整个字符串
        s = ' '.join(word[::-1] for word in s.split())   # 将每个单词反转
        return s

若不借助 strip() 和 split() 函数,写起来很麻烦,代码如下:

class Solution:

    # 反转s[i: j]
    def reverse(self, s, i, j):   # s是一个list
        while i < j:
            s[i], s[j] = s[j], s[i]
            i += 1
            j -= 1

    def reverseWords(self, s: str) -> str:
        s = list(s)
        # strip()
        start, end = 0, len(s) - 1
        n = len(s)
        while start < n and s[start] == ' ':
            start += 1
        while end >= 0 and s[end] == ' ':
            end -= 1
        if start > end:
            return ''

        # 去除中间多余的空格, 并且把字符串挪到最前面        
        i, j = 0, start
        while j <= end:
            if s[j] == ' ':
                if s[j - 1] == ' ':   # 多个空格
                    j += 1
                else:
                    s[i] = s[j]   # 只有1个空格
                    i += 1
                    j += 1
            else:   # 字母
                s[i] = s[j]
                i += 1
                j += 1

        n = i   # 有效字符串的长度
        self.reverse(s, 0, n - 1)
        i = 0
        while i < n:
            j = i # 找到i开始的整个单词
            while j < n and s[j] != ' ':
                j += 1
            # 此时, j指向单词的最后一个字母后的空格或者字符串结束处
            self.reverse(s, i, j - 1)
            i = j + 1 # 跳到下个单词的第一个
        
        return ''.join(s[:n])   # n是有效字符串的长度

剑指Offer58-II.左旋转字符串

剑指 Offer 58 - II. 左旋转字符串

使用整体反转+局部反转就可以实现反转单词顺序的目的

思路:先局部反转再整体反转 

class Solution:
    def reverse(self, s: list, start, end):
        while start < end:
            s[start], s[end] = s[end], s[start]
            start += 1
            end -= 1

    def reverseLeftWords(self, s: str, n: int) -> str:
        # 先反转前n个
        res = list(s)
        self.reverse(res, 0, n-1)
        # 再反转n+1到末尾
        self.reverse(res, n, len(res)-1)
        # 再整个反转
        self.reverse(res, 0, len(res)-1)
        return "".join(res) 

28. 找出字符串中第一个匹配项的下标 

28. 找出字符串中第一个匹配项的下标

(一)KMP

KMP主要应用在字符串匹配的场景中,其思想是当出现字符串不匹配的情况时,可以知道一部分之前已经匹配的文本内容,利用这些信息避免从头再去做匹配

如:文本串aabaabaaf(长度为n),模式串aabaaf(长度为m),要在文本串里匹配模式串

  • 暴力:两层for循环,遍历两个字符串,挨个匹配。时间复杂度O(m*n)
  • KMP:匹配过程O(n),单独生成next数组是O(m)。时间复杂度O(m+n)

next数组是一个前缀表,用来回退,记录了模式串与文本串不匹配时,模式串应该从哪里开始重新匹配。定义前缀表为:记录下标i(包括i)之前的字符串中有多长的相同前后缀

  • 前缀:包含首字母,不包含尾字母的所有连续子串
  • 后缀:包含尾字母,不包含首字母的所有连续子串

求得最长相同前后缀的长度就是对应前缀表的元素。找到了最长相等的前后缀,匹配失败的位置是后缀子字符串的后一个字符,找到与其相同的前缀,从后面重新匹配即可

关键:寻找匹配失败位置的前一位在前缀表中的元素,即为要跳转到的重新匹配的下标位置

(二)代码 

class Solution:

    # 构造next数组,即前缀表(将前缀表直接作为next数组)
    def getNext(self, next: List[int], s: str):    # s为模式串
        # step1:初始化next数组
        j = 0   # j为前缀末尾位置
        next[0] = 0   # 只有一个字符的字符串相同前后缀的最大长度是0
        for i in range(1, len(s)):   # i为后缀末尾位置
            # step2:若前缀和后缀对应的字符不相同
            while s[i] != s[j] and j>0:   # 是while而不是if,因为若不相同要连续回退
                j = next[j-1]   # j要回退到前一位next数组的值的下标位置
            # step3:若前缀和后缀对应的字符相同
            if s[i] == s[j]:
                j += 1   # j还代表着i包括i之前子串的最长相等前后缀长度
            next[i] = j 

    # 在haystack(文本串)里匹配needle(模式串)
    def strStr(self, haystack: str, needle: str) -> int:
        next = [0]*len(needle)
        self.getNext(next, needle)
        j = 0   # j为模式串起始位置
        for i in range(len(haystack)):   # i为文本串起始位置
            while haystack[i] != needle[j] and j>0:
                j = next[j-1]   # j就要从next数组中寻找下一个匹配的位置
            if haystack[i] == needle[j]:
                j += 1  # 若相同, i和j同时向后移动
            if j == len(needle):   # 若j指向了模式串的末尾,说明模式串完全匹配文本串的某个子串了
                return i-len(needle)+1   # 返回模式串在文本串中匹配时的第一个字符的位置
        return -1

459. 重复的子字符串

459. 重复的子字符串

复习KMP: 

  • 适用场景:给你一个字符串,判断另一个字符串是不是在这个字符串里出现过
  • KMP算法在查找过程中遇到不匹配的地方,直接跳到上一次匹配的地方继续匹配(因为有计算好的next数组)
  • next数组:以各个字符串为结尾的子串的最长相等前后缀的集合

若一个字符串是由重复子串组成的,那么它的最小重复单位就是它的最长相等前后缀不包含的那个子串。如:字符串 abababab,最长相等前后缀为 ababab,故不包含的就是ab

数组长度 - 最长相等前后缀的长度,相当于第一个重复子串的长度,也就是一个重复周期的长度。如果这个周期可以被整除,说明整个数组就是这个周期的循环

class Solution:

    # KMP求next数组(记录的就是最长相等前后缀的长度)
    def getNext(self, next: List[int], s: str):
        j = 0
        next[0] = 0
        for i in range(1, len(s)):
            while s[i] != s[j] and j>0:
                j = next[j-1]
            if s[i] == s[j]:
                j += 1
            next[i] = j

    def repeatedSubstringPattern(self, s: str) -> bool:
        next = [0]*len(s)
        self.getNext(next, s)   # "ababab"  [0,0,1,2,3,4]
        # next[-1] != 0说明字符串有相同的前后缀
        # next[-1] 就是最长相等前后缀的长度
        # len(s)-next[-1] 就是重复子串的长度
        if next[-1] != 0 and len(s) % (len(s)-next[-1]) == 0:   
            return True
        else:
            return False

总结:使用KMP可以解决两类经典问题,匹配问题(28题)和重复子串问题(459题)

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

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

相关文章

机器学习:监督学习、无监督学习、半监督学习、强化学习

1 引言 机器学习是一种人工智能领域的技术&#xff0c;它旨在让计算机通过学习数据和模式&#xff0c;而不是明确地进行编程来完成任务。机器学习分为监督学习&#xff08;Supervised Learning&#xff09;、无监督学习&#xff08;Unsupervised Learning&#xff09;、半监督…

算法笔记(Java)——动态规划

动态规划方法论 动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的&#xff0c;这一点就区分于贪心&#x…

网络安全策略应包含哪些?

网络安全策略是保护组织免受网络威胁的关键措施。良好的网络安全策略可以确保数据和系统的保密性、完整性和可用性。以下是一个典型的网络安全策略应包含的几个重要方面&#xff1a; 1. 强化密码策略&#xff1a;采用强密码&#xff0c;要求定期更换密码&#xff0c;并使用多因…

form-data 提交文件请求远程调用

文件请求方法 /*** 上传图文消息内的图片 获取url* 富文本内的图片** param file*/public static String uploadMediaGetUrl(File file) throws IOException {if (!file.exists()) {return null;}String responseData null;try {String url "http://localhost:8503/fil…

Spring Boot集成单元测试调用dao,service

文章目录 Spring Boot集成单元测试调用dao&#xff0c;service1 添加相关依赖2 新建测试类 Spring Boot集成单元测试调用dao&#xff0c;service 1 添加相关依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st…

VirtualBox配置宿主机和虚拟机网络互通+外网访问

VirtualBox 版本&#xff1a;7.0 虚拟机版本&#xff1a;CentOS-7-x86_64-Everything-1804_2.iso 宿主机版本&#xff1a;Windows 10-21H2 VirtualBox 和 虚拟机安装 省略~ VirtualBox 配置 在虚拟机的【设置】选项中配置两张网卡&#xff0c;图下图所示&#xff0c;网卡一用…

Vue3 基础知识点汇总

1.vue3 基础 1.1vue3基础及创建 npm init vue@latest1.2.熟悉项目目录及关键文字 1.3 组合式API-setup 1.4.组合式 API reactive 和ref 函数 (都是为了生成响应式数据)

【ArcGIS Pro二次开发】(55):给多个要素或表批量添加字段

在工作中可能会遇到这样的场景&#xff1a;有多个GDB要素、表格&#xff0c;或者是SHP文件&#xff0c;需要给这个要素或表添加相同的多个字段。 在这种情况下&#xff0c;手动添加就变得很繁琐&#xff0c;于是就做了主个工具。 需求具体如下图&#xff1a; 左图是待处理数据…

测试的概念

测试职责 需求分析 测试分析 设计测试用例 执行测试用例 掌握自动化测试技术 验证产品是否实现了应该实现的功能,或者实现了不应该实现的功能 在整个软件生命周期中&#xff0c;测试是一个贯穿始终的过程&#xff0c;它包含了不同阶段和不同类型的测试,以此来保证软件工程的稳…

金融翻译难吗,如何做好金融翻译?

我们知道&#xff0c;金融翻译涉及企业经济这块的&#xff0c;是影响各公司发展很重要的一方面&#xff0c;翻译做得好&#xff0c;可以促进公司内外的交流&#xff0c;及时掌握各种信息&#xff0c;做好应对。那么&#xff0c;金融翻译难吗&#xff0c;如何做好金融翻译&#…

第五章 Opencv图像处理框架实战 5-3 图像阈值与平滑处理

图像阈值 ret, dst cv2.threshold(src, thresh, maxval, type) src&#xff1a; 输入图&#xff0c;只能输入单通道图像&#xff0c;通常来说为灰度图 dst&#xff1a; 输出图 thresh&#xff1a; 阈值 maxval&#xff1a; 当像素值超过了阈值&#xff08;或者小于阈值&am…

【C进阶】回调函数(指针进阶2,详解,小白必看)

目录 6. 函数指针数组 6.1简单计算器 6.2函数指针数组实现计算器 7. 指向函数指针数组的指针(仅作了解即可) 8.回调函数 8.1关于回调函数的理解​编辑 8.1.1用回调函数改良简单计算器 8.2qsort库函数的使用 8.2.1冒泡排序 8.2.2qsort的概念 8.3冒泡排序思想实现qsor…

数据结构--基础知识

数据结构是什么&#xff1f; 数据结构是计算机科学中研究数据组织、存储和管理的方法和原则。它涉及存储和操作数据的方式&#xff0c;以便能够高效地使用和访问数据。 相关内容 基本组成 数组&#xff08;Array&#xff09;&#xff1a;数组是一种线性数据结构&#xff0c;…

MySql005——使用SQL创建数据库和表

在《MySql000——MySql数据库的下载、安装以及使用图形化工具创建数据库和表》中&#xff0c;我们使用图形化工具MySQL Workbench创建数据库和表&#xff0c;下面我们将使用SQL来实现这一过程 一、数据库操作 1.1、创建数据库 1.1.1、创建MySQL数据库通用写法 使用 create 命…

ts一些常用符号

非空断言操作符(!) 具体是指在上下文中当类型检查器无法断定类型时&#xff0c;一个新的后缀表达式操作符 ! 可以用于断言操作对象是非 null 和非 undefined 类型。具体而言&#xff0c;x! 将从 x 值域中排除 null 和 undefined 。 1. 赋值时忽略 undefined 和 null function…

Simulink仿真模块 - Saturation Dynamic

Saturation Dynamic将输入信号限制在动态饱和上界和下界值之间 在仿真库中的位置为&#xff1a;Simulink / Discontinuities 模型为&#xff1a; 说明 Saturation Dynamic 模块产生输出信号&#xff0c;该信号是以来自输入端口 up 和 lo 的饱和值为界的输入信号的值。 输入输…

【已解决】windows7添加打印机报错:加载Tcp Mib库时的错误,无法加载标准TCP/IP端口的向导页

windows7 添加打印机的时候&#xff0c;输入完打印机的IP地址后&#xff0c;点击下一步&#xff0c;报错&#xff1a; 加载Tcp Mib库时的错误&#xff0c;无法加载标准TCP/IP端口的向导页 解决办法&#xff1a; 复制以下的代码到新建文本文档.txt中&#xff0c;然后修改文本文…

PHP+mysql鲜花销售商城网站html5在线鲜花花店购物订购系统

花店订购管理系统&#xff0c;是基于php编程语言&#xff0c;mysql数据库开发&#xff0c;本系统分为用户和管理员两个角色&#xff0c;其中用户可以注册登陆系统&#xff0c;查看分类&#xff0c;搜索鲜花&#xff0c;查看鲜花详情&#xff0c;加入购物车&#xff0c;生成订单…

【MySQL】模具数据转移处理

系列文章 C#底层库–MySQLBuilder脚本构建类&#xff08;select、insert、update、in、带条件的SQL自动生成&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/129179216 C#底层库–MySQL数据库操作辅助类&#xff08;推荐阅读&#xff0…

【phaser微信抖音小游戏开发002】hello world!

执行效果&#xff1a; 将以下代码文本内容&#xff0c;放入到game.js中即可。目录结构如下图 import ./js/libs/weapp-adapter import ./js/libs/symbolGameGlobal.window.scrollTo () > { };//防止真机出错 import Phaser from ./js/phaser//引入Phaservar {windowWidth, …