6、Z字形变换
将一个给定字符串根据给定的行数,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 “LEETCODEISHIRING” 行数为 3 时,排列如下:
L C I R
E T O E S I I G
E D H N
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:“LCIRETOESIIGEDHN”。
请你实现这个将字符串进行指定行数变换的函数:
解答:本题只要找到相应的数学规律就十分容易,算法的时间复杂度和空间复杂度都能维持在O(n)。
class Solution:
def convert(self, s: str, numRows: int) -> str:
outputS=""
n=len(s)
if numRows==1:
return s
elif numRows==2:
for i in range(2):
k=i
while k<n:
outputS=outputS+s[k]
k=k+2
return outputS
else:
k=0
while k<n:
outputS=outputS+s[k]
k=k+2*numRows-2
for i in range(1,numRows-1):
k1=i
k2=2*numRows-2-i
while k1<n:
outputS=outputS+s[k1]
if k2<n:
outputS=outputS+s[k2]
k1=k1+2*numRows-2
k2=k2+2*numRows-2
k=numRows-1
while k<n:
outputS=outputS+s[k]
k=k+2*numRows-2
return outputS
算法的运行时间是64 ms,内存消耗是13.8 MB。
7、整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
解答:把数变成列表,用alist.reverse()或者自己写一个反转的语句,看看哪个效率高。
class Solution:
def reverse(self, x: int) -> int:
if x==0:
return 0
else:
xList=list(str(abs(x)))
xList.reverse()
#n=len(xList)
#for i in range(n//2):
#temp=xList[i]
#xList[i]=xList[n-1-i]
#xList[n-1-i]=temp
if xList[0]=='0':
xList=xList[1:]
if x<0:
x2=int("-"+"".join(xList))
else:
x2=int("".join(xList))
if x2 > 2 ** 31-1 or x2 < -2 ** 31:
return 0
else:
return x2
自己编的反转要60 ms ,13.6 MB。用alist.reverse()之后运行时间变成了40 ms,内存消耗为13.7 MB,不变。可见还是系统自带的函数功能更强。
8、字符串转换整数 (atoi)
请你来实现一个 atoi 函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
本题中的空白字符只包括空格字符 ’ ’ 。
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
该题有很多细节需要处理,例如输入"-"的情况,有+出现的情况等。尤其是需要排出的各类情况,不要遗漏。
class Solution:
def myAtoi(self, str: str) -> int:
n=len(str)
i=0
while i<n and str[i]==' ':
i=i+1
if i==n or n==0:
return 0
str=str[i:]
num=""
if str[0]=='-':
num=num+"-"
for i in str[1:]:
if '0'<=i and i<='9':
num=num+i
else:
break
if len(num)<2:#防止"-"的形式出现
return 0
elif '0'<=str[0]<='9':
for i in str:
if '0'<=i and i<='9':
num=num+i
else:
break
if len(num)<1:#防止全是字母的形式出现
return 0
elif str[0]=="+":
for i in str[1:]:
if '0'<=i and i<='9':
num=num+i
else:
break
if len(num)<1:#防止全是字母的形式出现
return 0
else:
return 0
num=int(num)
INT_MAX=2**31-1
INT_MIN=-2**31
if num>INT_MAX:
return INT_MAX
elif num<INT_MIN:
return INT_MIN
else:
return num
因为一直在加情况,代码比较乱,也懒得整理了。
最后运行时间是40 ms,内存消耗是13.8 MB
9、回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
注:负数不是回文数
class Solution:
def isPalindrome(self, x: int) -> bool:
if x<0:
return False
else:
xStr=str(x)
n=len(xStr)
if n==1:
return True
else:
a=1
for i in range(n//2):
if xStr[i]!=xStr[n-1-i]:
a=0
break
if a==1:
return True
else:
return False
运行时间是76 ms,内存消耗是13.7 MB。
这里比较有意思的是return False打印的是false。
10、正则表达式匹配(hard)
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
解法一:这种乱七八糟的题的一个朴素的想法就是用递归,只要每次能减少就行。
如果p空,那么s必须要空才行。此外事实上我们只需要考虑’*'位于p[1]的情况,这是p[0]p[1]可以当0个使用或者当n个p[0]使用,n必然>=1,我们在一次调用中只需要让这对组合使用0次或一次就行,这样要么把p[0]p[1]组合删去,要么在首字母匹配后可以将s[0]删去,如此一来这样的递归肯定能够终止,问题也就解决了。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
firstMatch= len(s)>0 and (p[0]=="." or p[0]==s[0])#首字母匹配
if len(p)>=2 and p[1]=="*":#可以是零个或任意多个,多个时s[0]与p[0]要匹配
return self.isMatch(s,p[2:]) or (firstMatch and self.isMatch(s[1:],p))
else:
if firstMatch:#检验第一个是否符合
return self.isMatch(s[1:],p[1:])
else:
return False
因为本题的情况很少,所以递归的代码相当简洁,只是效率低下,运行时间为1284 ms只超过了27.33%的用户,内存消耗为13.4 MB。
解法二:
事实上我们可以基于上述的递归方法进行改进。改进递归法的思路就是储存一些递归中间结果,避免重复运算。还有就是代码里的切片可以改为标记左右点,这样能剩下不少内存也能节约时间。
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if not p:
return not s
self.memory={}#初始化记忆,要加self的
self.buildMemory(s,p)#构建缓存
return self.memory[(s,p)]
def buildMemory(self,s,p):#self必不可少
if not p:
return not s
if (s,p) in self.memory:
return self.memory[(s,p)]
firstMatch= len(s)>0 and (p[0]=="." or p[0]==s[0])#首字母匹配
if len(p)>=2 and p[1]=="*":#可以是零个或任意多个,多个时s[0]与p[0]要匹配
result=self.buildMemory(s,p[2:]) or (firstMatch and self.buildMemory(s[1:],p))#firstMatch必不可少
else:
if firstMatch:#检验第一个是否符合
result=self.buildMemory(s[1:],p[1:])
else:
result=False
self.memory[(s,p)]=result
return result
运行时间为52 ms,超过93.12%的用户,但是内存基本不变