【PythonCode】力扣Leetcode6~10题Python版

【PythonCode】力扣Leetcode6~10题Python版

前言

力扣Leetcode是一个集学习、刷题、竞赛等功能于一体的编程学习平台,很多计算机相关专业的学生、编程自学者、IT从业者在上面学习和刷题。
在Leetcode上刷题,可以选择各种主流的编程语言,如C++、JAVA、Python、Go等。还可以在线编程,实时执行代码,如果代码通过了平台准备的测试用例,就可以通过题目。
本系列中的文章从Leetcode的第1题开始,记录我用Python语言提交的代码和思路,受个人能力限制,只是实现功能通过用例,我没有每题都研究最优的实现方法,供Python学习参考。

6. N 字形变换

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如下:
在这里插入图片描述
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“PAHNAPLSIIGYIR”。

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:
输入:s = “PAYPALISHIRING”, numRows = 3
输出:“PAHNAPLSIIGYIR”
示例 2:
输入:s = “PAYPALISHIRING”, numRows = 4
输出:“PINALSIGYAHRPI”
示例 3:
输入:s = “A”, numRows = 1
输出:“A”
提示:
1 <= s.length <= 1000
s 由英文字母(小写和大写)、‘,’ 和 ‘.’ 组成
1 <= numRows <= 1000

代码实现:

class Solution:def convert(self, s: str, numRows: int) -> str:if numRows == 1:return szlist = ["" for _ in range(numRows)]i, flag = 0, 1for a in s:zlist[i] += aif i == 0 or i == numRows-1:flag = -flagi -= flagreturn "".join(zlist)

解题思路:题目有两个输入,一个是字符串s,一个是行数numRows,最终要求输出的也是一个字符串。第一步,要将字符串s进行z字形排列,最后输出时,要按行来排列字符串,这里可以在代码中巧妙地满足这两个条件。创建一个列表,列表中先初始化三个空字符串,用列表的下标表示z字形排列时的行数,将字符串s中的每一个字符按z字形规则依次拼接到对应的行,最后再将列表中的字符串全部拼接返回。

再来看z字形规则如何排列,第一个字符从第一行开始排列,用一个变量i表示当前的行,用一个变量flag表示现在是向下排列还是向上排列,flag的值为1或-1,每从s中取完一个字符,即将行数减去flag,这样行数就会向下或向上变化。当移动到第一行或最后一行时,flag的值翻转。

当只有一行时,是题目的边界情况,此时z字形排列的结果即字符串本身,直接返回即可。

7. 整数反转

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
示例 4:
输入:x = 0
输出:0
提示:
-2^31 <= x <= 2^31 - 1

代码实现:

class Solution:def reverse(self, x: int) -> int:y = str(x)num = int("-" + y[:0:-1]) if y[0] == "-" else int(y[::-1])return 0 if (num > 2 ** 31 - 1) or (num < -2 ** 31) else num

解题思路:这题虽然难度是中等,但其实实现比较简单。要将一个数字翻转,Python中可以直接将数字转换成字符串,用字符串切片的方式翻转,再转换回数字。因为输入数字可能是负数,所以做一次判断就行,并且题目要求,如果数字超过边界值时返回0,所以要判断一次结果的数字范围。代码可以直接用三元运算的语法来写,非常简洁。三元运算语法参考:详解Python中的三元运算。

8. 字符串转换整数 (atoi)

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数)。

函数 myAtoi(string s) 的算法如下:

  • 读入字符串并丢弃无用的前导空格。
  • 检查下一个字符(假设还未到字符末尾)为正还是负号,读取该字符(如果有)。 确定最终结果是负数还是正数。
  • 如果两者都不存在,则假定结果为正。 读入下一个字符,直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
  • 将前面步骤读入的这些数字转换为整数(即,“123” -> 123, “0032” -> 32)。如果没有读入数字,则整数为 0 。
  • 必要时更改符号(从步骤 2 开始)。 如果整数数超过 32 位有符号整数范围 [−2^31, 2^31 − 1],需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31 的整数应该被固定为 −2^31 ,大于 2^31 − 1 的整数应该被固定为 2^31 − 1 。 返回整数作为最终结果。

注意:
本题中的空白字符只包括空格字符 ’ ’ 。
除前导空格或数字后的其余字符串外,请勿忽略任何其他字符。

示例 1:
输入:s = “42”
输出:42
解释:
第 1 步:“42”(当前没有读入字符,因为没有前导空格)
第 2 步:“42”(当前没有读入字符,因为这里不存在 ‘-’ 或者 ‘+’)
第 3 步:“42”(读入 “42”) 解析得到整数 42 。 由于 “42” 在范围 [-231, 231 - 1] 内,最终结果为 42 。
示例 2:
输入:s = " -42"
输出:-42
解释:
第 1 步:" -42"(读入前导空格,但忽视掉)
第 2 步:" -42"(读入 ‘-’ 字符,所以结果应该是负数)
第 3 步:" -42"(读入 “42”) 解析得到整数 -42 。 由于 “-42” 在范围 [-231, 231 - 1] 内,最终结果为 -42 。
示例 3:
输入:s = “4193 with words”
输出:4193
解释:
第 1 步:“4193 with words”(当前没有读入字符,因为没有前导空格)
第 2 步:“4193 with words”(当前没有读入字符,因为这里不存在 ‘-’ 或者 ‘+’)
第 3 步:“4193 with words”(读入 “4193”;由于下一个字符不是一个数字,所以读入停止) 解析得到整数 4193 。 由于 “4193” 在范围 [-231, 231 - 1] 内,最终结果为 4193 。
提示:
0 <= s.length <= 200
s 由英文字母(大写和小写)、数字(0-9)、’ ‘、’+‘、’-’ 和 ‘.’ 组成

代码实现:

class Solution:def myAtoi(self, s: str) -> int:s = s.strip()if not s:return 0flag = '+'if s[0] == '+':s = s[1:]elif s[0] == '-':s = s[1:]flag = '-'istr = ''for a in s:if a in ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']:istr += aelse:breakif not istr:return 0num = int(flag+istr)if num < -2 ** 31:return -2 ** 31elif num > 2 ** 31 - 1:return 2 ** 31 - 1else:return num

解题思路:此题在题目中已经完整地描述了步骤,代码基本就是按照这些步骤来写,并且满足每一个步骤中的要求。题目说的字符串中是可以有非数字字符的,如果有非数字字符,则找到连续的最多的数字字符,将这些字符转换成整数,如果没有数字字符,则返回整数0。代码中用一个flag变量来记录数字的正负符号,最终转换整数时拼接上flag。转换完成之后再做一次边界判断。

9. 回文数

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

例如,121 是回文,而 123 不是。

示例 1:
输入:x = 121
输出:true
示例 2:
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数。
提示:
-2^31 <= x <= 2^31 - 1

代码实现:

class Solution:def isPalindrome(self, x: int) -> bool:return str(x) == str(x)[-1::-1]

解题思路:本题也比较简单,回文数要求正序和倒序读都一样,直接将数字转换成字符串,比较正序和倒序是否相等。不过这里也可以简单分析下,有两种比较明显的非回文数的情况,一是负数,二是正数中第一个数字不可能为0,所以如果整数的最后一个数字为0(能被10整除),则不是回文数。

10. 正则表达式匹配

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符
‘*’ 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s 的,而不是部分字符串。

示例 1:
输入:s = “aa”, p = “a”
输出:false
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:s = “aa”, p = “a*”
输出:true
解释:因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:s = “ab”, p = “.*”
输出:true
解释:“.*” 表示可匹配零个或多个(‘*’)任意字符(‘.’)。
提示:
1 <= s.length <= 20
1 <= p.length <= 30
s 只包含从 a-z 的小写字母。
p 只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符。

代码实现:

class Solution:def isMatch(self, s: str, p: str) -> bool:m, n = len(s), len(p)dp = [[False for _ in range(m+1)] for _ in range(n+1)]dp[0][0] = Truefor i in range(1, n+1):if p[i-1] == '*':if i-2 >= 0:dp[i][0] = dp[i-2][0]for i in range(1, n+1):for j in range(1, m+1):if p[i-1] == s[j-1] or p[i-1] == '.':dp[i][j] = dp[i-1][j-1]if p[i-1] == '*':dp[i][j] = dp[i-2][j]if p[i-2] == s[j-1] or p[i-2] == '.':dp[i][j] = dp[i][j] or dp[i][j-1]return dp[n][m]

解题思路:正则表达式中的 . 和 * 分别表示匹配任意一个字符和匹配前一个字符任意多次,现在需要自己写代码实现这两个规则。题目中的输入是两个字符串s和p,点号和星号是出现在字符串p中,我们的目标是实现正则表达式的规则,然后输出p是否能按正则的规则匹配到s。

每次从字符串p中取出一个字符或者 字符+星号 的组合,并在s中进行匹配。对于p中一个字符而言,它只能在s中匹配一个字符,匹配的方法具有唯一性,而对于p中 字符+星号 的组合而言,它可以在s中匹配任意自然数个字符,并不具有唯一性。因此,应从p的右侧往左侧来分析,如果p的最后一个字符是星号,星号仅能和它的前一个字符组合,如果p的最后一个字符不是星号,则它只能与s中的一个字符比较。这样从右往左分析,要判断s与p是否匹配,就是需要判断最右端是否匹配,以及剩余的子串是否匹配(子问题),这样就可以用动态规划的方法来求解。动态规划可以参考:循序渐进,搞懂什么是动态规划。

按照动态规划的解题步骤,第一步先定义问题的状态,用dp[i][j]表示p的前i个字符和s的前j个字符能否匹配,如果字符串p的长度为n,字符串s的长度为m,则dp[n][m]就是问题的答案。

第二步为列出状态转移方程,如果p[i]==s[j],说明p的第i个字符和s的第j个字符可以匹配,那么就看前面的字符是否可以匹配,状态转移方程:dp[i][j]=dp[i−1][j−1]。如果p[i]==‘.’,因为它可以代表任何字符,所以一定可以和s的第j个匹配上,也只需要看前面的字符是否可以匹配,状态转移方程:dp[i][j]=dp[i−1][j−1]。因为星号可以匹配0次、1次或多次,所以如果p[i]==‘*’,又需要分情况讨论。

如果p的第i个字符是星号,那么能不能与s的第j个字符匹配上,就看星号的前一个字符,也就是第i-1个字符。如果p[i-1]与s[j]匹配不上,那星号可以表示匹配0次,状态转移方程:dp[i][j]=dp[i−2][j]。如果p[i-1]与s[j]匹配,那么可以匹配上,此时星号表示匹配1次,同时,要考虑星号匹配多次的情况,也就是说,s[j]前还可能有与s[j]相等的字符,所以,这里p[i]的星号与p[i-1]的字符组合匹配s[j]后,p[i]的星号与p[i-1]继续保留,重复利用(这样就可以把匹配多次转换成反复匹配1次),直到遇到匹配0次的情况,p[i]的星号才利用完,状态转移方程:dp[i][j]=dp[i][j−1]。当然,这里并不是星号一定要匹配尽可能多的字符,可以介于于正则表达式中的“贪婪模式”与​“非贪婪模式”之间,比如点号和星号组合可以把s中的字符全部匹配完,但是字符串p的前面还有其他字符,所以这里点号和星号组合就不能全部匹配完,要留适当的一部分字符给p中前面的这些字符匹配,所以要允许状态不变,即dp[i][j]=dp[i][j]。

第三步为状态初始化,如果字符串s和字符串p都是空字符串,是可以匹配的,初始化为:dp[0][0]=True,并初始化一个长度为n+1乘m+1的dp数组。因为p中的星号可以表示0次,所以还有可能s为空,p不为空,如p=‘a*’, p='a*b*'等,这种情况s为空,在上面的状态转移方程中不存在s[j],所以也要进行初始化。

关于初始化,本题中还有一个注意事项,因为初始化dp[0][0]是字符串s和p都为空,所以字符串非空时,dp[i][j]中的i和j是从1开始的,而字符串的索引是从0开始的,所以索引要比状态编号减一,也就是说,上面的分析中,在代码中s或p的索引要再减1。同时,因为状态编号从1开始,所以代码需要遍历到m+1和n+1,也是dp数组大小为n+1乘m+1的原因。

当然,此题也可以用递归的方式实现,参考下方代码(不再具体分析了)。不过,使用递归时,时间复杂度满足不了力扣的要求,这就需要用到Python中的@cache装饰器,通过缓存来降低时间复杂度。参考:Python中的@cache有什么妙用?。

class Solution:def isMatch(self, s: str, p: str) -> bool:@cachedef DFS(i, j):if j == len(p):return i == len(s)firstMatch = i < len(s) and (s[i] == p[j] or p[j] == '.')if j + 1 < len(p) and p[j + 1] == '*':return DFS(i, j + 2) or (firstMatch and DFS(i + 1, j))return firstMatch and DFS(i + 1, j + 1)return DFS(0, 0)

相关阅读

PythonCode】力扣Leetcode1~5题Python版

📢欢迎 点赞👍 收藏⭐ 评论📝 关注 如有错误敬请指正!

☟ 学Python,点击下方名片关注我。☟

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Backend - Windows 自动排程

目录 一、创建排程 1. Windows 键 R 打开"运行"。输入taskschd.msc 回车&#xff0c;进入工作排程器。 2. 在右侧“动作”导航栏中&#xff0c;点击“建立工作”。 3. 设置“一般”、“触发程序”、“动作”。 4. 排程管理 二、运行问题 1. 文件位置相关问题…

软考高级:BPR 和 BPM概念和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

中电金信:技术实践|Flink维度表关联方案解析

导语&#xff1a;Flink是一个对有界和无界数据流进行状态计算的分布式处理引擎和框架&#xff0c;主要用来处理流式数据。它既可以处理有界的批量数据集&#xff0c;也可以处理无界的实时流数据&#xff0c;为批处理和流处理提供了统一编程模型。 维度表可以看作是用户来分析数…

【AI+应用】一步步搭建聊天机器人搭配多种国内外大模型以及api接口调用

如果你看过我之前写的一篇文章 【AI应用】怎么快速制作一个类chatGPT套壳网站&#xff0c; 你可能顺利地使用chatGPT、Gemini&#xff0c; 用得很happy。 突然有一天&#xff0c;你发现一些网站&#xff0c;除了chatGPT、Gemini &#xff0c;还可以切换使用国内外其他的大模型…

你为什么是你,而不是别人?认识人格的力量

你为什么是你&#xff0c;而不是别人&#xff1f;让你做自我介绍&#xff0c;你会怎么描述自己呢&#xff1f; 人格心理学是心理学的一门重要分支学科。探求、描述和揭示个体思想、情绪及行为的独特模式&#xff0c;综合个人与环境诸多影响因素&#xff0c;对现实社会中的个人作…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:ColumnSplit)

将子组件纵向布局&#xff0c;并在每个子组件之间插入一根横向的分割线。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 可以包含子组件。 ColumnSplit通过分割线限制子组件的高度。初始…

电视盒子解析安装包失败,安卓4.4安装不了kodi的解决方法,如何安装kodi

有些安卓电视或者电视盒子的安卓系统版本太低、自身架构或者屏蔽了安装其他应用的功能&#xff0c;下载的Kodi apk安装包提示无法安装&#xff0c;解析程序包时出现问题、解析出错无法安装、[INSTALL_FAILED_OLDER_SDK]、此应用与您的电视不兼容。 解决方法&#xff1a; 1、3…

linux下重启ORACLE

切换到oracle用户 su - oracle 登录oracle sqlplus / as sysdba 启动数据库 startup 退出数据库 exit 启动监听 lsnrctl start FINISH

【Java设计模式】二十三、解释器模式

文章目录 1、解释器模式2、案例 1、解释器模式 计算一个表达式的值&#xff0c;比如12-34-7&#xff0c;单纯的定义方法或函数很难适配所有&#xff0c;因为数值和运算符可以有无数种组合。 //用于n个整数相加 public static int add(Integer ... arr) {int sum 0;for (Inte…

Xpay源支付2.8.8免授权聚合免签系统

产品介绍 XPay是专为个人站长打造的聚合免签系统&#xff0c;拥有卓越的性能和丰富的功能。采用全新轻量化的界面UI&#xff0c;让您可以更加方便快捷地解决知识付费和运营赞助的难题。同时&#xff0c;它基于高性能的ThinkPHP 6.1.2 Layui 2.8.10 PearAdmin架构&#xff0c…

Learn OpenGL 08 颜色+基础光照+材质+光照贴图

我们在现实生活中看到某一物体的颜色并不是这个物体真正拥有的颜色&#xff0c;而是它所反射的(Reflected)颜色。物体的颜色为物体从一个光源反射各个颜色分量的大小。 创建光照场景 首先需要创建一个光源&#xff0c;因为我们以及有一个立方体数据&#xff0c;我们只需要进行…

C语言从入门到熟悉------第四阶段

指针 地址和指针的概念 要明白什么是指针&#xff0c;必须先要弄清楚数据在内存中是如何存储的&#xff0c;又是如何被读取的。如果在程序中定义了一个变量&#xff0c;在对程序进行编译时&#xff0c;系统就会为这个变量分配内存单元。编译系统根据程序中定义的变量类型分配…