一、字符串转换整数 (atoi)
此题为leetcode第8题
思路:当然如果用正则表达式的话可能只需寥寥一行,但此题并不是想考察python的正则表达式。此题的常规做法就是按照规则一点一点来,并没有什么特殊的知识点。不过还有一种叫自动机的解法,我认为比较有意思,它抽象出start、end、signed、number这几个状态来,遍历字符串,根据规则来进行状态转移。这样的自动机如下图所示:
也可以用下面的表格表示:
# 常规解法
class Solution:
def myAtoi(self, str: str) -> int:
# 规则
for i in range(len(str)):
if str[i] == ' ':
i += 1
else:
str = str[i:]
break
res = []
a = 0
positive = True
for k, s in enumerate(str):
if k == 0 and s == '+':
positive = True
elif k == 0 and s == '-':
positive = False
elif not (ord(s)-48 >= 0 and ord(s)-48<=9):
break
else:
num_flag = True
res.append(ord(s)-48)
if res:
res = res[::-1]
for i in range(len(res)):
a += 10**i * res[i]
if not positive:
a = -a
if a < 0:
return max(a, -2**31)
elif a >= 0:
return min(a, 2**31-1)
else:
return 0
class Automation:
def __init__(self):
self.state = 'start'
self.sign = 1
self.res = 0
self.states = {
'start': ['start', 'signed', 'num', 'end'],
'signed': ['end', 'end', 'num', 'end'],
'num': ['end', 'end', 'num', 'end'],
'end': ['end', 'end', 'end', 'end']
}
def get_state(self, c):
if c.isspace():
return self.states[self.state][0]
elif c == '+' or c == '-':
return self.states[self.state][1]
elif c.isdigit():
return self.states[self.state][2]
else:
return self.states[self.state][3]
def get(self, c):
self.state = self.get_state(c)
if self.state == 'num':
self.res = self.res * 10 + int(c)
self.res = min(INT_MAX, self.res) if self.sign == 1 else min(-INT_MIN, self.res)
if self.state == 'signed':
self.sign = 1 if c == '+' else -1
class Solution:
def myAtoi(self, str: str) -> int:
# 自动机
auto = Automation()
for s in str:
auto.get(s)
return auto.sign * auto.res
二、最长公共前缀
此题为leetcode第14题
思路:从左往右纵向比较即可
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
# 纵向比较
if len(strs) == 0:
return ''
if len(strs) == 1:
return strs[0]
res = []
for i in range(len(strs[0])):
for j in range(len(strs)):
if len(strs[j]) <= i or strs[j][i] != strs[0][i]:
return ''.join(res)
res.append(strs[0][i])
return ''.join(res)
三、二进制求和
此题为leetcode第67题
思路:由于a、b字符串长度不一定相等,因此可以右对齐然后前面填0使两者对其,使用字符串的zfill()方法。然后从后面依次遍历,设置一个初始为0的carry标志位,如果字符为’1’,那么carry+1。如果carry为2或0,那么当前位变为0;如果carry为1或3,那么当前位边为1。当然还有进位需要考虑,carry为2或3时需要进1位,carry为0或1时不需要进位,那么carry变为carry // 2即可。
class Solution:
def addBinary(self, a: str, b: str) -> str:
n = max(len(a), len(b))
a, b = a.zfill(n), b.zfill(n)
res = ''
carry = 0
for i in range(n - 1, -1, -1):
if a[i] == '1':
carry += 1
if b[i] == '1':
carry += 1
if carry % 2 == 0:
res = '0' + res
elif carry % 2 == 1:
res = '1' + res
carry //= 2
if carry == 1:
res = '1' + res
return res
四、反转字符串
此题为leetcode第344题
思路:迭代解法:前后两个指针,不重合时依次字符互换;递归解法:前后两个指针所指的字符互换后,其所夹的子串为子问题,传入helper函数中递归。
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# 迭代
left, right = 0, len(s) - 1
while left < right:
s[left], s[right] = s[right], s[left]
left += 1
right -= 1
class Solution:
def reverseString(self, s: List[str]) -> None:
"""
Do not return anything, modify s in-place instead.
"""
# 递归
def helper(left, right):
if left < right:
s[left], s[right] = s[right], s[left]
helper(left+1, right-1)
helper(0, len(s)-1)
五、验证回文串
此题为leetcode第125题
思路:首先可以都转为小写字母。然后首尾两个指针,依次对比,如果两边都为数字或字母且相等,那么指针就都移动一位;如果都为数字或字母但不相等,那么直接退出返回False;如果有哪个指针为非字母或数字,那么这一轮他就移动一步,忽略这个字母。当然可以用比较pythonic的写法,两行搞定
# 解法1
class Solution:
def isPalindrome(self, s: str) -> bool:
s = s.lower()
left, right = 0, len(s) - 1
def check(ss):
if 'a' <= ss <= 'z' or '0' <= ss <= '9':
return True
else:
return False
while left < right:
if check(s[left]) and check(s[right]):
if s[left] != s[right]:
return False
left += 1
right -= 1
elif check(s[left]) and not check(s[right]):
right -= 1
elif not check(s[left]) and check(s[right]):
left += 1
else:
left += 1
right -= 1
return True
# 解法2
class Solution:
def isPalindrome(self, s: str) -> bool:
s = ''.join(filter(str.isalnum, s.lower()))
return s == s[::-1]
六、验证回文字符串II
此题为leetcode第680题
思路:和上一题比较类似,也是首尾双指针,如果字符相等的话就各自移动一位;如果不相等话,就忽略左边一位或忽略右边一位,继续比较,如果又遇上不相等的,那就不是回文字符串。
class Solution:
def validPalindrome(self, s: str) -> bool:
def check(l, r,):
while l < r:
if s[l] == s[r]:
l += 1
r -= 1
else:
return False
return True
left, right = 0, len(s) - 1
while left < right:
if s[left] == s[right]:
left += 1
right -= 1
else:
return check(left + 1, right) or check(left, right - 1)
return True