目录
剑指 Offer 14- I. 剪绳子
动态规划解法
状态: dp[n] = n米的最大乘积
递推: dp[i] = max([max(dp[k], k) * max(dp[i-k], i-k) for k in range(i//2+1)])
初始化 all set 0 dp[1]=0 dp[2] = 1
class Solution:
def cuttingRope(self, n: int) -> int:
# 状态: dp[n] = n米的最大乘积
# 递推: dp[i] = max([max(dp[k], k) * max(dp[i-k], i-k) for k in range(i//2+1)])
# 初始化 all set 0 dp[1]=0 dp[2] = 1
dp = [0] * (n+1)
dp[2] = 1
for i in range(3, n+1):
dp[i] = max([max(dp[k], k) * max(dp[i-k], i-k) for k in range(i//2+1)])
return dp[n]
数学解析:
class Solution:
def cuttingRope(self, n: int) -> int:
if n <= 3: return n - 1
a, b = n // 3, n % 3
if b == 0: return int(math.pow(3, a))
if b == 1: return int(math.pow(3, a - 1) * 4)
return int(math.pow(3, a) * 2)
剑指 Offer 19. 正则表达式匹配
状态: dp[i, j]表示s[:i], p[:j]的匹配情况
如果正则p为空,除非字符串s也为空,否则都是False
递推一下,求dp[i, j]
-
如果 s [ i ] = p [ j ] s[i] = p[j] s[i]=p[j]字母,且相同,则 d p [ i , j ] = d p [ i − 1 , j − 1 ] dp[i,j] = dp[i-1,j-1] dp[i,j]=dp[i−1,j−1]
-
如果 p [ j ] = ′ . ′ p[j] = '.' p[j]=′.′,则无所谓 s [ i ] s[i] s[i]是什么, d p [ i , j ] = d p [ i − 1 , j − 1 ] dp[i,j] = dp[i-1,j-1] dp[i,j]=dp[i−1,j−1]
-
如果 p [ j ] = ′ ∗ ′ p[j]='*' p[j]=′∗′,则又要分情况讨论:
情况1: 重复0次,则p的最后两个字母 c ∗ c* c∗可以被丢弃, d p [ i , j ] = d p [ i , j − 2 ] dp[i,j] = dp[i,j-2] dp[i,j]=dp[i,j−2]
情况2: 重复1次或者1次以上,则如果 s [ i ] s[i] s[i]与 p [ j ] p[j] p[j]可以匹配,则少重复一遍也可以被匹配上, 所以如果有 s [ i ] = p [ j − 1 ] s[i]=p[j-1] s[i]=p[j−1], 则有 d p [ i , j ] = d p [ i , j − 1 ] dp[i,j] = dp[i,j-1] dp[i,j]=dp[i,j−1]
class Solution:
def isMatch(self, s: str, p: str) -> bool:
# 状态: dp[i, j]表示s[:i], p[:j]的匹配情况
n = len(s)
m = len(p)
dp = [[False] * (m+1) for _ in range(n+1)]
for i in range(n+1): # 字符串s
for j in range(m+1): # 正则式p
if j == 0: # 空正则
dp[i][j] = (i==0)
else:
if i >= 1 and (s[i-1] == p[j-1] or p[j-1] == '.'): # 情况1,2合并
dp[i][j] = dp[i-1][j-1]
if p[j-1] == '*':
if j>=2 and dp[i][j-2]: # 情况3.1
dp[i][j] = True
else: # 情况3.2
if (j>=2 and i>=1 and p[j-2] == s[i-1]) or p[j-2] == '.' :
dp[i][j] = dp[i-1][j]
return dp[n][m]