文章目录
前言
会记录自己看过的一些leetcode小题记。希望自己能够慢慢成长起来。不再是一个小垃圾。
583. Delete Operation for Two Strings
Given two words word1 and word2, find the minimum number of steps required to make word1 and word2 the same, where in each step you can delete one character in either string.
Example 1:
Input: “sea”, “eat”
Output: 2
Explanation: You need one step to make “sea” to “ea” and another step to make “eat” to “ea”.
这道题是最近面试被问到的一个题,第一反应是编辑距离的变体,但是动态规划真的是让我头大。我一定好好加油啊!
哈哈哈
看着leetcode的解题思路整理一下。后边补上编辑距离的题。
Approch
- 遍历求得最长公共子序列,但是时间复杂度为 O ( 2 m a x ( m , n ) ) O(2^{max(m,n)}) O(2max(m,n)), 空复杂度 O ( m a x ( m , n ) ) O(max(m,n)) O(max(m,n))
#########################################################################
# 583. Delete Operation for Two Strings
#########################################################################
# solution 1: 递归求最长公共子序列
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
len1 = len(word1)
len2 = len(word2)
return len1 + len2 - 2 * self.LongestCommonSubsequence(word1, word2, len1, len2)
def LongestCommonSubsequence(self, word1, word2, len1, len2):
if len1 == 0 or len2 == 0:
return 0
if word1[len1 - 1] == word2[len2 - 1]:
return 1 + self.LongestCommonSubsequence(word1, word2, len1 - 1, len2 - 1)
else:
return max(self.LongestCommonSubsequence(word1, word2, len1 - 1, len2),
self.LongestCommonSubsequence(word1, word2, len1, len2 - 1))
# solution2:空间换时间 求得最长公共子序列. java代码可以 但是python不行
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
len1 = len(word1)
len2 = len(word2)
memo = [[0] * (len1 + 1) for _ in range(len2 + 1)]
return len1 + len2 - 2 * self.LongestCommonSubsequence(word1, word2, len1, len2, memo)
def LongestCommonSubsequence(self, word1, word2, len1, len2, memo):
if len1 == 0 or len2 == 0:
return 0
if memo[len1][len2] > 0:
return memo[len1][len2]
if word1[len1 - 1] == word2[len2 - 1]:
memo[len1][len2] = 1 + self.LongestCommonSubsequence(word1, word2, len1 - 1, len2 - 1, memo)
else:
memo[len1][len2] = max(
self.LongestCommonSubsequence(word1, word2, len1 - 1, len2, memo),
self.LongestCommonSubsequence(word1, word2, len1, len2 - 1, memo))
return memo[len1][len2]
# solution 3 : 动态规划求得最长公共子序列
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
len1 = len(word1)
len2 = len(word2)
dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
for i in range(1, len1 + 1):
for j in range(1, len2 + 1):
if word1[i - 1] == word2[j - 1]:
dp[i][j] = 1 + dp[i-1][j-1]
else:
dp[i][j] = max(dp[i][j-1], dp[i-1][j])
return len1 + len2 - 2 * dp[len1][len2]
# solution4: 动态规划,不求最长公共子序列
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
len1 = len(word1)
len2 = len(word2)
dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
for i in range(len1 + 1):
for j in range(len2 + 1):
if i == 0 or j == 0:
dp[i][j] = i+j
elif word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1 + min(dp[i][j-1], dp[i-1][j])
return dp[len1][len2]
72. Edit Distance
#########################################################################
# 72. Edit Distance
#########################################################################
# 动态规划求得编辑距离
# if word1[i - 1] == word2[j - 1],
# then no more operation is needed and dp[i][j] = dp[i - 1][j - 1].
# If word1[i - 1] != word2[j - 1], we need to consider three cases.
# Replace word1[i - 1] by word2[j - 1] (dp[i][j] = dp[i - 1][j - 1] + 1);
# If word1[0..i - 1) = word2[0..j) then delete word1[i - 1] (dp[i][j] = dp[i - 1][j] + 1);
# If word1[0..i) + word2[j - 1] = word2[0..j) then insert word2[j - 1] to word1[0..i) (dp[i][j] = dp[i][j - 1] + 1).
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
len1 = len(word1)
len2 = len(word2)
if len1 == 0 or len2 == 0:
return len1 + len2
# 定义len2 * len1 的二维数组
dp = [[0] * (len1 + 1) for _ in range(len2 + 1)]
# 遍历每一行
for i in range(len2 + 1):
# 遍历每一列
for j in range(len1 + 1):
if i == 0 or j == 0:
dp[i][j] = i + j
elif word1[i - 1] == word2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
# 用w2的当前元素替换w1的当前元素
replace = dp[i - 1][j - 1] + 1
#
delete = dp[i - 1][j] + 1
insert = dp[i][j - 1] + 1
dp[i][j] = min(replace, insert, delete)
return dp[len2][len1]
10. Regular Expression Matching
class Solution:
# s, pattern都是字符串
def isMatch(self, s, pattern):
# write code here
if len(s) == 0 and len(pattern) == 0:
return True
if len(s) != 0 and len(pattern) == 0:
return False
# 第二个字符是*
if len(pattern) > 1 and pattern[1] == '*':
# 首字母相同或者pattern第一个为.
if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'):
return self.isMatch(s, pattern[2:]) or \
self.isMatch(s[1:], pattern[2:]) or \
self.isMatch(s[1:], pattern)
else:
return self.isMatch(s, pattern[2:])
# 第二个不是*,首字母相同或者pattern[0]为 .
if len(s) > 0 and (s[0] == pattern[0] or pattern[0] == '.'):
return self.isMatch(s[1:], pattern[1:])
return False
# solution2: 动态规划
# 动态匹配s[i] p[j]
class Solution:
# s, pattern都是字符串
def isMatch(self, s, p):
memo = {}
def dp(i, j):
if (i, j) not in memo:
if len(p) == j:
res = i == len(s)
else:
fistmatch = len(s) > i and p[j] in {s[i], '.'}
if len(p) > j + 1 and p[j + 1] == '*':
res = dp(i, j + 2) or fistmatch and dp(i + 1, j)
else:
res = dp(i + 1, j + 1) and fistmatch
memo[i, j] = res
return memo[i, j]
return dp(0, 0)
62. Unique Paths
#########################################################################
# 62. Unique Paths
#########################################################################
# 因为机器人只能向下或者向右走,所以每一个格子dp[i][j] = dp[i-1][j] + dp[i][j-1]
class Solution(object):
def uniquePaths(self, m, n):
"""
:type m: int
:type n: int
:rtype: int
"""
dp = [[1 for _ in range(m)] for _ in range(n)]
for i in range(1, n):
for j in range(1, m):
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[n-1][m-1]
63. Unique Paths II
class Solution(object):
def uniquePathsWithObstacles(self, obstacleGrid):
"""
:type obstacleGrid: List[List[int]]
:rtype: int
"""
row = len(obstacleGrid)
col = len(obstacleGrid[0])
if obstacleGrid[0][0] == 1:
return 0
obstacleGrid[0][0] = 1
for i in range(1, row):
obstacleGrid[i][0] = int(obstacleGrid[i][0] == 0 and obstacleGrid[i-1][0] == 1)
for j in range(1, col):
obstacleGrid[0][j] = int(obstacleGrid[0][j] == 0 and obstacleGrid[0][j-1] == 1)
for i in range(1, row):
for j in range(1, col):
if obstacleGrid[i][j] == 0:
obstacleGrid[i][j] = obstacleGrid[i-1][j] + obstacleGrid[i][j-1]
else:
obstacleGrid[i][j] = 0
return obstacleGrid[row-1][col-1]
64. Minimum Path Sum
#########################################################################
# 64. Minimum Path Sum
#########################################################################
# 初始化第一行和第一列为逐元素的加和,之后的每一个格子的值为上边和左边的元素的min加上当前元素的值。
class Solution(object):
def minPathSum(self, grid):
"""
:type grid: List[List[int]]
:rtype: int
"""
row = len(grid)
col = len(grid[0])
for i in range(1, col):
grid[0][i] += grid[0][i-1]
for j in range(1, row):
grid[j][0] += grid[j-1][0]
for i in range(1, row):
for j in range(1, col):
grid[i][j] += min(grid[i-1][j], grid[i][j-1])
return grid[row-1][col-1]
85. Maximal Rectangle
#########################################################################
# 85. Maximal Rectangle
#########################################################################
# 用三个变量分别记录长方形的长宽高。
# height[j]记录第j列 1 的个数。
# left[j]记录左边的边界。
# right[i]记录右边的边界。
class Solution(object):
def maximalRectangle(self, matrix):
"""
:type matrix: List[List[str]]
:rtype: int
"""
if matrix == []:
return 0
row = len(matrix)
col = len(matrix[0])
height = [0] * col
left = [0] * col
right = [col - 1] * col
maxA = 0
for i in range(row):
cur_left = 0
cur_right = row - 1
# 更新height
for j in range(col):
if matrix[i][j] == '1':
height[j] += 1
else:
height[j] = 0
# 更新left
for j in range(col):
if matrix[i][j] == '1':
left[j] = max(left[j], cur_left)
else:
left[j] = 0
cur_left = j + 1
for j in range(col-1, -1, -1):
if matrix[i][j] == '1':
right[j] = min(right[j], cur_right)
else:
right[j] = col - 1
cur_right = j - 1
for j in range(col):
maxA = max(maxA, (right[j] - left[j] + 1) * height[j])
return maxA
87. Scramble String
#########################################################################
# 87. Scramble String
#########################################################################
# 跟二叉树的镜像有点相似。这道题主要是将两个字符串分为两部分,然后分为两种情况进行比较,
# 情况1:s1的右边跟s2的右边符合isScramble 且同时 s1的左边跟s2的左边符合isScramble
# 情况2:s1的右边i个字符跟s2的左边i个符合isScramble 且同时 s1的左边跟s2的右边符合isScramble
class Solution(object):
def isScramble(self, s1, s2):
"""
:type s1: str
:type s2: str
:rtype: bool
"""
len1 = len(s1)
len2 = len(s2)
if (len1 != len2 ) or (sorted(s1) != sorted(s2)):
return False
if s1 == s2 or len1 < 3:
return True
for i in range(1, len1):
if self.isScramble(s1[0:i], s2[0:i]) and self.isScramble(s1[i:], s2[i:]) \
or self.isScramble(s1[0:i], s2[len2-i:]) and self.isScramble(s1[i:], s2[:len2-i]):
return True
return False