LeetCode-算法:71-80(Python)
71. 简化路径
思路
- 以"/"分隔输入路径path保存在catelog中
- 不为空或不为当前目录".“或上一级目录”…“时,将目录名插入ans列表,遇到”.“时不作操作,遇到”…"时ans.pop()掉最后一个目录,即返回上一级目录
- 连接ans中的目录
class Solution(object):
def simplifyPath(self, path):
"""
:type path: str
:rtype: str
"""
catelog = path.split('/')
ans = list()
for item in catelog:
if item and item not in [".", ".."]:
ans.append(item)
elif item == ".":
pass
elif item == "..":
if not ans:
pass
else:
ans.pop()
return "/"+"/".join(ans)
72. 编辑距离
思路
word1插入 等价 word2删除
word1删除 等价 word2插入
word1替换 等价 word2替换
动态规划
- m为word1的长度,n为word2的长度。当word1或word2其一为空或都为空时,需要n+m次操作
- 创建dp数组,初始化dp[i]0,同理初始化dp[0][j]
- 计算dp数组中的值dp[i][j]
- dp[i-1][j]为word1的前i-1个字符和word2的前j个字符的操作距离。在word1后操作1个字符得到dp[i][j],即dp[i-1][j]+1
- dp[i][j-1]为word1的前i个字符和word2的前j-1个字符的操作距离。在word2后操作1个字符得到dp[i][j],即dp[i][j-1]+1
- dp[i-1][j-1]为word1的前i-1个字符和word2的前j-1个字符的操作距离。word1的第i个字符不等于word2的第j个字符时,dp[i-1][j-1]操作1个字符得到dp[i][j],即dp[i][j-1]+1;word1的第i个字符等于word2的第j个字符时,dp[i-1][j-1]无需操作得到dp[i][j],即dp[i][j-1]
- 得到状态转移方程
- word[i]!=word[j]时,dp[i][j]=min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i][j-1]+1)==1+min(dp[i-1][j], dp[i][j-1], dp[i][j-1])
- word[i]==word[j]时,dp[i][j]=min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i][j-1])==1+min(dp[i-1][j], dp[i][j-1], dp[i][j-1]-1)
栗子:
e | 5 | 4 | 4 | 3 |
---|---|---|---|---|
s | 4 | 3 | 3 | 2 |
r | 3 | 2 | 2 | 2 |
o | 2 | 2 | 1 | 2 |
h | 1 | 1 | 2 | 3 |
# | 0 | 1 | 2 | 3 |
- | # | r | o | s |
class Solution(object):
def minDistance(self, word1, word2):
"""
:type word1: str
:type word2: str
:rtype: int
"""
m, n = len(word1), len(word2)
if n*m == 0:
return n+m
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1):
dp[i][0] = i
for j in range(n+1) :
dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) if word1[i-1] != word2[j-1] else 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]-1)
return dp[-1][-1]
73. 矩阵置零
思路
- 创建row, col保存matrix中值为0的行和列
- 将row中的行元素置0,将col中的列元素置0
class Solution(object):
def setZeroes(self, matrix):
"""
:type matrix: List[List[int]]
:rtype: None Do not return anything, modify matrix in-place instead.
"""
if not matrix:
return matrix
n, m = len(matrix), len(matrix[0])
row, col = set(), set()
for i in range(n):
for j in range(m):
if matrix[i][j]==0:
row.add(i)
col.add(j)
for r in row:
matrix[r]=[0 for _ in range(m)]
for c in col:
for i in range(n):
matrix[i][c]=0
return matrix
74. 搜索二维矩阵
思路
遍历matrix元素,查找是否存在target,是返回True,否返回False
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
n = len(matrix)
for i in range(n):
if target in matrix[i]:
return True
return False
思路
matrix全部元素看作有序数组,然后使用二分查找target
class Solution(object):
def searchMatrix(self, matrix, target):
"""
:type matrix: List[List[int]]
:type target: int
:rtype: bool
"""
if not matrix:
return False
m , n = len(matrix), len(matrix[0])
left, right =0, m*n-1
while left <= right:
mid = (left+right)//2
r, c = mid//n, mid%n
if matrix[r][c] == target:
return True
elif matrix[r][c] > target:
right = mid - 1
else:
left = mid + 1
return False
75. 颜色分类
思路
一个直观的解决方案是使用计数排序的两趟扫描算法。
首先,迭代计算出0、1 和 2 元素的个数,然后按照0、1、2的排序,重写当前数组。
class Solution(object):
def sortColors(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
n = len(nums)
n0, n1, n2 = 0, 0, 0
for num in nums:
if num == 0:
n0 += 1
elif num == 1:
n1 += 1
else:
n2 += 1
nums[:n0] = [0 for _ in range(n0)]
nums[n0:n0+n1] = [1 for _ in range(n1)]
nums[n0+n1:n0+n1+n2] = [2 for _ in range(n2)]
return nums
思路
快速排序
class Solution(object):
def sortColors(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
left, right = 0, len(nums)-1
def QuickSort(nums, left, right):
if left < right:
i = left
j = right
key = nums[i]
while i < j:
while i < j and nums[j] >= key:
j -= 1
nums[i] = nums[j]
while i < j and nums[i] < key:
i += 1
nums[j] = nums[i]
nums[i] = key
QuickSort(nums, left, i-1)
QuickSort(nums, i+1, right)
return nums
QuickSort(nums, left, right)
return nums
思路
- left记录0的边界,right记录2的边界
- cur遇到0时,和left交换值,更新left+=1,cur+1;cur遇到2时,和right交换值,更新right-=1,cur不变;当cur遇到1时,cur+1
栗子:
class Solution(object):
def sortColors(self, nums):
"""
:type nums: List[int]
:rtype: None Do not return anything, modify nums in-place instead.
"""
left, right, cur = 0, len(nums)-1, 0
while cur <= right:
if nums[cur] == 0:
nums[cur], nums[left] = nums[left], nums[cur]
left += 1
cur += 1
elif nums[cur] == 2:
nums[cur], nums[right] = nums[right], nums[cur]
right -= 1
else:
cur += 1
return nums
76. 最小覆盖子串
思路
- l, r双指针,r往右走(r = r+1);字符串t的字母和对应的个数记录为dict_t(键为字母,值为字母个数),字符串s的字母和对应的个数记录为dict_s;required记录dict_t的长度,即字母数,当dict_s和dict_t相同字母的个数相同时,ack加1;ans记录s中包含t所有字母的最小子串的长度,初始化为无穷大;left, right记录ans的左边和右边
- 当required与ack相等时,即dist_s(s的子串s[l, r])中包含了dist_t(字符串t),如果r-l+1小于原ans,则更新ans=r-1+1, left=l, right=r。
- l往右走时(l = l+1),丢弃字母s[l],如果s[l]存在字符串t中,则ack减1,及dist_s中不再包含所有的dist_t。如果s[l]不存在字符串t中,大胆往右走,啥也不影响。
class Solution(object):
def minWindow(self, s, t):
"""
:type s: str
:type t: str
:rtype: str
"""
from collections import Counter
if not s or not t or len(t) > len(s):
return ""
if t == s:
return t
n = len(s)
dict_t, dict_s = dict(Counter(t)), dict()
required, ack = len(dict_t), 0
l, r, left, right, ans = 0, 0, 0, 0, float("inf")
while r < n:
char = s[r]
# Python 字典(Dictionary) get() 函数返回指定键的值,如果值不在字典中返回默认值
dict_s[char] = dict_s.get(char, 0) + 1
if char in dict_t and dict_s[char] == dict_t[char]:
ack += 1
while l <= r and required == ack:
if r-l+1<ans:
left, right = l, r
ans = r-l+1
char = s[l]
dict_s[char] -= 1
if char in dict_t and dict_s[char] < dict_t[char]:
ack -= 1
l += 1
r += 1
return "" if ans == float("inf") else s[left:right+1]
77. 组合
思路
回溯
class Solution(object):
def combine(self, n, k):
"""
:type n: int
:type k: int
:rtype: List[List[int]]
"""
def backtrack(first=1, ele=list()):
if len(ele[:]) == k:
ans.append(ele[:])
for i in range(first, n+1):
ele.append(i)
backtrack(i+1, ele)
ele.pop()
ans = list()
backtrack()
return ans
78. 子集
思路
栗子:
nums = [1, 2, 3]
初始化ans=[[]]
遍历nums的元素num:
-
num = 1:
- pre=[], ans+=[pre + [num] for pre in ans] = [[]] + [[]+[1]] = [[], [1]]
-
num = 2:
- pre=[], ans+=[pre + [num] for pre in ans] = [[], [1]] + [[]+[2]] = [[], [1], [2]]
- pre=[1], ans+=[pre + [num] for pre in ans] = [[], [1], [2]] + [[1]+[2]] = [[], [1], [2], [1, 2]]
-
num = 3:
- pre = [], ans+=[pre + [num] for pre in ans] = ans + [[]+[3]] = [[], [1], [2], [1, 2], [3]]
- pre = [1], ans+=[pre + [num] for pre in ans] = ans + [[1]+[3]] = [[], [1], [2], [1, 2], [3], [1, 3]]
- pre = [2], ans+=…= ans + [[2]+[3]] = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3]]
- pre = [1, 2], ans+=…= ans + [[1, 2]+[3]] = [[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
class Solution(object):
def subsets(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
ans = [[]]
for num in nums:
ans += [pre + [num] for pre in ans]
return ans
79. 单词搜索
思路
- searchStart寻找board中与word第一位字符相等的位置记录在start列表中
- searchPath寻找word是否存在board中,从start的位置开始从direction中上下左右的4个方向找出改单词是否在board中
class Solution(object):
def exist(self, board, word):
"""
:type board: List[List[str]]
:type word: str
:rtype: bool
"""
len_word = len(word)
len_m = len(board)
len_n = len(board[0])
direction = [[-1, 0], [1, 0], [0, -1], [0, 1]] # 方向:上下左右
if len_word > len_m * len_n:
return False
def searchStart(first):
for i in range(len_m):
for j in range(len_n):
if board[i][j] == first:
start.append([i, j])
start = list()
searchStart(word[0][0])
if not start:
return False
def searchPath(start_x, start_y, index_w):
if index_w == len(word) - 1:
return board[start_x][start_y] == word[index_w]
if board[start_x][start_y] == word[index_w]:
visited[start_x][start_y] = True
for d in direction:
new_x = start_x+d[0]
new_y = start_y+d[1]
if new_x >= 0 and new_x < len_m and new_y >= 0 and new_y < len_n\
and not visited[new_x][new_y] and searchPath(new_x, new_y, index_w+1):
return True
visited[start_x][start_y] = False
for i in range(len(start)):
visited = [[False]*len_n for _ in range(len_m)]
if searchPath(start[i][0], start[i][1], 0):
return True
return False
80. 删除排序数组中的重复项 II
思路
是26. 删除排序数组中的重复项的进阶,双指针
- 当nums长度n小于等于2时,直接返回n
- 因为nums是一个排序数组,无需排序。初始化索引i为0,count默认为已出现1次,索引j从1开始。当nums[i]等于nums[j]时,如果nums[j]出现的次数少于2次,i往右移动一步,并令nums[i] = nums[j];如果count大于2,则索引i不往右移动,count加1,索引j继续往右移动。当nums[i]不等于nums[j]时,i往右移动一步,并令nums[i] = nums[j],count设为1
class Solution(object):
def removeDuplicates(self, nums):
"""
:type nums: List[int]
:rtype: int
"""
n = len(nums)
if n <= 2:
return n
i, count = 0, 1
for j in range(1, n):
if nums[i] == nums[j]:
if count < 2:
i += 1
nums[i] = nums[j]
count += 1
else:
i += 1
count = 1
nums[i] = nums[j]
return i+1
丢一只我家谢谢