方法1:使用正则表达式,格式为 import re
,re.match(r"^...$", s)
,其中 ^
表示匹配 s 的开始,$
表示匹配 s 的结尾,...
就是自己写的表达式。匹配成功会返回一个对象,则为 True,否则为 False。
Python 常见的正则表达式符号:
\d
:数字;?
:0次或1次;*
:0次到n次;+
:1次到n次;\.
:匹配 ".";[]
:字符集合;()
:分组;.
:任意字符。
注意:
(1)"-.123" 也是合法的,对应代码中的 \d*
;
(2)如果不加结尾符 $
,则对于 "12e" 这种也会匹配成功(比如 12e+5,它会匹配中间的 12e,从而造成错误),因此需要在末尾加上 $
。
# -*- coding:utf-8 -*-
import re # 导入正则表达式
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
if re.match(r"^[+-]?\d*(\.\d+)?([eE][+-]?\d+)?$", s): # 匹配成功会返回一个对象
return True
else:
return False
方法2:尝试将 s 转化为 float(s)
,转换成功返回 True,否则返回 False。因此需要用到 Python 的 try
、except
语句。
# -*- coding:utf-8 -*-
class Solution:
# s字符串
def isNumeric(self, s):
# write code here
try: # 转化成功返回 True
float(s)
return True
except: # 转化失败返回 False
return False
因为要保证相对位置,所以只能用空间和时间复杂度均为 O(n) 的算法。(如果不需要保证相对位置,可以用双指针,类似于快排 partition 部分的操作,空间 O(1),时间 O(n))
# -*- coding:utf-8 -*-
class Solution:
def reOrderArray(self, array):
# write code here
le, ri = [], []
for num in array:
if num & 1:
le.append(num)
else:
ri.append(num)
return le + ri
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def FindKthToTail(self, head, k):
# write code here
slow = fast = head
while fast and k:
fast = fast.next
k -= 1
if k > 0: # k 大于链表长度
return None
while fast:
slow = slow.next
fast = fast.next
return slow
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def EntryNodeOfLoop(self, pHead):
# write code here
is_cycle = False
slow = fast = pHead
while fast and fast.next:
slow = slow.next
fast = fast.next.next
if slow == fast: # 快慢指针相遇
is_cycle = True
break
if not is_cycle: # 没有环
return None
begin = pHead
while begin != slow: # 一步一步走,相遇即为环入口
begin = begin.next
slow = slow.next
return begin
可以使用迭代和递归,迭代就是指针的移动和交换,容易实现。这里实现的递归的方法。
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回ListNode
def ReverseList(self, pHead):
# write code here
if not pHead or not pHead.next:
return pHead
second = pHead.next
newHead = self.ReverseList(second)
second.next = pHead
pHead.next = None # 断开
return newHead
# -*- coding:utf-8 -*-
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
# 返回合并后列表
def Merge(self, pHead1, pHead2):
# write code here
pre1, cur1, cur2 = None, pHead1, pHead2
while cur1 and cur2: # 合并后的链表为链表1
if cur1.val <= cur2.val:
pre1 = cur1
cur1 = cur1.next
elif not pre1:
pre1 = cur2
cur2 = cur2.next
pre1.next = cur1
else:
pre1.next = cur2
pre1 = pre1.next
cur2 = cur2.next
pre1.next = cur1
if not cur1 and pre1: # 链表1为空,直接接链表2
pre1.next = cur2
return pHead1
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
# write code here
if not pRoot1 or not pRoot2:
return False
return self.isHasSubtreeSame(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)
def isHasSubtreeSame(self, r1, r2):
if not r2:
return True
if not r1 or r1.val != r2.val:
return False
return self.isHasSubtreeSame(r1.left, r2.left) and self.isHasSubtreeSame(r1.right, r2.right)
将当前结点的左右子树的地址对调即可。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
# 返回镜像树的根节点
def Mirror(self, root):
# write code here
if not root:
return None
tmp = root.left # 防止交换后原先的 root.left 被修改
root.left = self.Mirror(root.right)
root.right = self.Mirror(tmp)
return root
要转化为判断根节点的左子树和右子树是否对称,因此需要另写一个函数递归判断。
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def isSymmetrical(self, pRoot):
# write code here
if not pRoot:
return True
return self.isSubtreeSym(pRoot.left, pRoot.right)
def isSubtreeSym(self, le, ri):
if not le and not ri: # 均为空
return True
if not le or not ri: # 有一个为空
return False
if le.val != ri.val: # 均不为空
return False
return self.isSubtreeSym(le.left, ri.right) and self.isSubtreeSym(le.right, ri.left)
按层的概念,从外到内一层一层填充。每次填充前,先记录每一层的左上角和右下角的位置。同时,还要对奇数行或奇数列的情况加 if 判断,防止出现重复填充的问题。
# -*- coding:utf-8 -*-
class Solution:
# matrix类型为二维列表,需要返回列表
def printMatrix(self, matrix):
# write code here
row, col = len(matrix) - 1, len(matrix[0]) - 1 # 右下角 (row, col)
ri = ci = 0 # 左上角 (ri, ci)
res = []
while ri <= row and ci <= col:
for i in range(ri, col + 1):
res.append(matrix[ri][i])
for i in range(ri + 1, row + 1):
res.append(matrix[i][col])
if ri != row: # 奇数行,只填充一次
for i in range(col - 1, ci - 1, -1):
res.append(matrix[row][i])
if ci != col: # 奇数列,只填充一次
for i in range(row - 1, ri, -1):
res.append(matrix[i][ci])
# 每填充一层之后,下一次填充的左上角位置为 (ri,ci),右下角位置为 (row,col)
ri += 1; ci += 1; row -= 1; col -= 1
return res
剑指 offer 终于过了一遍,大多数题目还是很简单的,但是题目具有代表性,涉及链表、数组、深搜回溯、字符串、数组、数学、位运算、动态规划等。