# Leetcode - 动态规划1

mhxin

## 5. 最长回文子串

def longestPalindrome(s):

if not s or len(s) < 2:
return s

n = len(s)

max_len = 1
start_idx = 0

# 依次以每个字符作为回文串的中心, 向两侧扩张
for i in range(n):
j = 0

# 当回文串的长度为奇数时
while  i - j >= 0 and i + j < n:
if s[i-j] == s[i + j]:
if 2 * j + 1 > max_len:
max_len = 2 * j + 1
start_idx = i - j
j += 1
else:
break

# 当回文串的长度为偶数时
j = 0
while  i - j - 1 >= 0 and i + j < n:
if s[i-j-1] == s[i + j]:
if 2 * (j + 1) > max_len:
max_len = 2 * (j + 1)
start_idx = i - j - 1
j += 1
else:
break

return s[start_idx: start_idx+max_len]


def longestPalindrome(s):
n = len(s)
dp = [[False] * n for _ in range(n)]
ans = ""

# 枚举子串的长度 l+1
for l in range(n):
# 枚举子串的起始位置 i，这样可以通过 j=i+l 得到子串的结束位置
for i in range(n):
j = i + l
if j >= len(s):
break
if l == 0:
dp[i][j] = True
elif l == 1:
dp[i][j] = (s[i] == s[j])
else:
dp[i][j] = (dp[i + 1][j - 1] and s[i] == s[j])
if dp[i][j] and l + 1 > len(ans):
ans = s[i:j+1]
return ans

## 72. 编辑距离

horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

$dp[i][j]$表示将word1的i位置变到word2的j位置所需要的步数。

\begin{align} dp[i][j] &=dp[i-1][j-1], if\quad word1[i]=word2[j] \\ dp[i][j]&=min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1,other\end{align}

Note：针对第一行、第一列要单独考虑，引入‘ ’， 如下图所示。


def minDistance(word1, word2):
if word1 == '':
return len(word2)
if word2 == '':
return len(word1)
n1 = len(word1)
n2 = len(word2)

dp = [[0] * (n2+1) for i in range(n1+1)]
for i in range(n1+1):
dp[i][0] = i
for i in range(n2+1):
dp[0][i] = i

for i in range(1, n1+1):
for j in range(1, n2+1):

# 状态转移方程
if word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = min(dp[i-1][j-1], dp[i][j-1], dp[i-1][j]) + 1
return dp[-1][-1]



def minDistance(word1, word2):
if word1 == '':
return len(word2)
if word2 == '':
return len(word1)
n1 = len(word1)
n2 = len(word2)
w1 = [i for i in range(n1+1)]
w2 = [i for i in range(n2+1)]
# 不添加下面的语句， 会超时

import functools
# functools.lru_cache会将中间的结果保存, 来避免大量的重复计算
@functools.lru_cache(None)

def helper(m, n):
if m == 1:
return w2[n-1]
if n == 1:
return w1[m-1]

if word1[m-1] == word2[n-1]:
return helper(m-1, n-1)
else:
return min(helper(m-1, n-1), helper(m-1, n), helper(m, n-1)) +1
return helper(n1+1, n2+1)


## 198. 打家劫舍

偷窃到的最高金额 = 1 + 3 = 4 。

偷窃到的最高金额 = 2 + 9 + 1 = 12 。

$dp(n) = max(dp(n-2) + nums(n), dp(n-1))$

• 当前元素偷: 前一个不能偷, 能偷的最大值等于$dp(n-2)+nums(n)$
• 当前元素不偷: 前一个元素能偷的最大值, 前一个元素偷不偷不要紧, 能偷的最大值为$dp(n-1)$
• 能偷的最大值为$dp(n) = max(dp(n-2) + nums(n), dp(n-1))$
def rob(nums):
if not nums:
return 0
if len(nums) == 1:
return nums[0]
if len(nums) == 2:
return max(nums[0], nums[1])
rob_money = [nums[0], max(nums[0], nums[1])]

n = len(nums)
for i in range(2, n):
rob_money[0], rob_money[1] = rob_money[1], max(rob_money[0]+nums[i], rob_money[1])

return rob_money[1]    

## 213. 打家劫舍 II

偷窃到的最高金额 = 1 + 3 = 4 。


def rob(nums):
if not nums:
return 0
if len(nums) == 1:
return nums[0]
if len(nums) == 2:
return max(nums[0], nums[1])
if len(nums) == 3:
return max(nums)

# 不偷第一个
dp = [nums[1], max(nums[1], nums[2])]
n = len(nums)
for i in range(3, n):
dp[0], dp[1] = dp[1], max(dp[0]+nums[i], dp[1])

money_without_first = dp[1]

# 不偷最后一个
dp = [nums[0], max(nums[0], nums[1])]
for i in range(2, n-1):
dp[0], dp[1] = dp[1], max(dp[0]+nums[i], dp[1])

money_without_last = dp[1]

return max(money_without_first, money_without_last)

## 516. 最长回文子序列

"bbbab"

4

"cbbd"

2

def longestPalindromeSubseq(s) -> int:
n = len(s)

if n <= 1 or s[::-1] == s:
return n

dp = [0]*n
for i in range(n-1, -1, -1):
temp = 0
dp[i] = 1
for j in range(i+1, n):
if s[i] == s[j]:
temp, dp[j] = dp[j], temp + 2
else:
temp = dp[j]
if dp[j-1] > dp[j]:
dp[j] = dp[j-1]
return dp[-1]


## 674. 最长连续递增序列

\begin{align} f(n)=\begin{cases}f(n-1)+1,if(nums[n-1]>nums[n-2])\\ 1,else\end{cases}\end{align}

def findLengthOfLCIS(nums) -> int:
if not nums or len(nums) == 0:
return 0

if len(nums) == 1:
return 1

# 状态转移方程为: dp(i) = dp(i-1) + 1 if nums[i] > nums[i-1] else 1

res = 1
dp = 1

n = len(nums)
for i in range(1, n):
if nums[i] > nums[i-1]:
dp = dp + 1
res = max(res, dp)
else:
dp = 1
return res


82 声望
12 粉丝
0 条评论