defuniquePaths(self, m:int, n:int)->int:
cur =[1]* n
for i inrange(1, m):for j inrange(1, n):
cur[j]+= cur[j-1]return cur[-1]defuniquePaths(self, m:int, n:int)->int:return comb(m + n -2, n -1)
defmaxProfit(self, prices: List[int])->int:
n =len(prices)if n ==0:return0
dp =[0]* n
minprice = prices[0]for i inrange(1,n):
minprice =min(minprice,prices[i])
dp[i]=max(dp[i-1],prices[i]-minprice)return dp[-1]
# 方法一:动态规划defexpandStr(self, s, left, right):while left >=0and right <len(s)and s[left]== s[right]:
left -=1
right +=1return left +1, right -1deflongestPalindrome(self, s:str)->str:
n =len(s)if n <2:return s
max_len =1
begin =0
dp =[[False]* n for _ inrange(n)]for i inrange(n):
dp[i][i]=Truefor L inrange(2, n +1):for i inrange(n):
j = L + i -1if j >= n:breakif s[i]!= s[j]:
dp[i][j]=Falseelse:if j - i <3:
dp[i][j]=Trueelse:
dp[i][j]= dp[i+1][j-1]if dp[i][j]and j - i +1> max_len:
max_len = j - i +1
begin = i
return s[begin: begin + max_len]# 方法二:中心扩展算法classSolution:defexpandAroundCenter(self, s, left, right):while left >=0and right <len(s)and s[left]== s[right]:
left -=1
right +=1return left +1, right -1deflongestPalindrome(self, s:str)->str:
start, end =0,0for i inrange(len(s)):
left1, right1 = self.expandAroundCenter(s, i, i)
left2, right2 = self.expandAroundCenter(s, i, i +1)if right1 - left1 > end - start:
start, end = left1, right1
if right2 - left2 > end - start:
start, end = left2, right2
return s[start: end +1]# 方法三:Manacher 算法defexpand(self, s, left, right):while left >=0and right <len(s)and s[left]== s[right]:
left -=1
right +=1return(right - left -2)//2deflongestPalindrome(self, s:str)->str:
end, start =-1,0
s ='#'+'#'.join(list(s))+'#'
arm_len =[]
right =-1
j =-1for i inrange(len(s)):if right >= i:
i_sym =2* j - i
min_arm_len =min(arm_len[i_sym], right - i)
cur_arm_len = self.expand(s, i - min_arm_len, i + min_arm_len)else:
cur_arm_len = self.expand(s, i, i)
arm_len.append(cur_arm_len)if i + cur_arm_len > right:
j = i
right = i + cur_arm_len
if2* cur_arm_len +1> end - start:
start = i - cur_arm_len
end = i + cur_arm_len
return s[start+1:end+1:2]
defminDistance(self, word1:str, word2:str)->int:
m, n =len(word1),len(word2)
dp =list(range(n +1))for i inrange(m):
lu = dp[0]
dp[0]= i +1for j inrange(n):
dp[j +1], lu =min(dp[j]+1, dp[j +1]+1, lu +int(word1[i]!= word2[j])), dp[j +1]return dp[-1]defminDistance(self, word1:str, word2:str)->int:
m, n =len(word1),len(word2)
dp =[[0for _ inrange(n +1)]for _ inrange(m +1)]for i inrange(m +1): dp[i][0]= i
for j inrange(n +1): dp [0][j]= j
for i inrange(1,m +1):for j inrange(1,n +1):
dp[i][j]=min(dp[i-1][j-1]+(0if word1[i-1]== word2[j-1]else1),
dp[i-1][j]+1,
dp[i][j-1]+1)return dp[m][n]
defminCut(self, s:str)->int:
n =len(s)
g =[[True]* n for _ inrange(n)]for i inrange(n -1,-1,-1):for j inrange(i +1, n):
g[i][j]=(s[i]== s[j])and g[i +1][j -1]
f =[float('inf')]* n
for i inrange(n):if g[0][i]:
f[i]=0else:for j inrange(i):if g[j +1][i]:
f[i]=min(f[i], f[j]+1)return f[n -1]
defcombine(self, n:int, k:int)-> List[List[int]]:# 排列组合的性质:C(m,n)=C(m-1,n)+C(m-1,n-1)if k > n or k ==0:return[]if k ==1:return[[i]for i inrange(1, n+1)]if k == n:return[[i for i inrange(1, n+1)]]
res = self.combine(n-1, k)for item in self.combine(n-1, k-1):
item.append(n)
res.append(item)return res
# 库函数defsubsets(self, nums: List[int])-> List[List[int]]:
res =[]for i inrange(len(nums)+1):for tmp in itertools.combinations(nums, i):
res.append(tmp)return res
# 迭代defsubsets(self, nums: List[int])-> List[List[int]]:
res =[[]]for i in nums:
res = res +[[i]+ num for num in res]return res
# 递归defsubsets(self, nums: List[int])-> List[List[int]]:
res =[]
n =len(nums)defhelper(i, tmp):
res.append(tmp)for j inrange(i, n):
helper(j +1,tmp +[nums[j]])
helper(0,[])return res
defsubsetsWithDup(self, nums):"""
:type nums: List[int]
:rtype: List[List[int]]
"""ifnot nums:return[]
n =len(nums)
res =[]
nums.sort()# 思路1defhelper1(idx, n, temp_list):if temp_list notin res:
res.append(temp_list)for i inrange(idx, n):
helper1(i +1, n, temp_list +[nums[i]])# 思路2defhelper2(idx, n, temp_list):
res.append(temp_list)for i inrange(idx, n):if i > idx and nums[i]== nums[i -1]:continue
helper2(i +1, n, temp_list +[nums[i]])
helper2(0, n,[])return res
defsubsetsWithDup(self, nums: List[int])->List[List[int]]:
nums.sort()
ans =set()
cur =[]
self.dfs(nums,0, cur, ans)return[list(x)for x in ans]defdfs(self, nums, u, cur, ans):if u ==len(nums):
ans.add(tuple(cur))return
cur.append(nums[u])
self.dfs(nums, u +1,cur, ans)
cur.pop()
self.dfs(nums, u +1, cur, ans)
@lru_cache(None)defgenerateParenthesis(self, n):if n ==0:return['']
ans =[]for c inrange(n):for left in self.generateParenthesis(c):for right in self.generateParenthesis(n-1-c):
ans.append('({}){}'.format(left,right))return ans
defwordBreak(self, s:str, wordDict: List[str])-> List[str]:
@lru_cache(None)defbacktrack(index:int)-> List[List[str]]:if index ==len(s):return[[]]
ans =list()for i inrange(index +1,len(s)+1):
word = s[index:i]if word in wordSet:
nextWordBreaks = backtrack(i)for nextWordBreak in nextWordBreaks:
ans.append(nextWordBreak.copy()+[word])return ans
wordSet =set(wordDict)
breakList = backtrack(0)return[" ".join(words[::-1])for words in breakList]
defreverseWords(self, s: List[str])->None:"""
Do not return anything, modify s in-place instead.
"""
i =0for j inrange(len(s)):if s[j]!=' ':continue
self.reverse(s, i,j)
i = j +1
self.reverse(s, i,len(s))
self.reverse(s,0,len(s))defreverse(self, s, i, j):for k inrange(i,(i + j)//2):
g = j -1- k + i
s[k], s[g]= s[g], s[k]
# 找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。# 输入: k = 3, n = 7, 输出: [[1,2,4]]defcombinationSum3(self, k, n):
res =[]defbacktrack(path, index, n, k):if n ==0and k ==0:#单次结束并添加的条件,和为n, 总数为k.
res.append(path[:])#添加路径到结果中,注意[:]的使用returnfor i inrange(index,10):#遍历的路径,也就是1-9.
path.append(i)#添加进路径
backtrack(path, i +1, n - i, k -1)#递归,并index加1防止重复值加入。
path.pop()#回溯
backtrack([],1, n, k)return res
# Python 内部已经实现了常用的排列与组合的函数在itertools模块下
product 笛卡尔积 (有放回抽样排列)
permutations 排列 (不放回抽样排列)
combinations 组合没有重复 (不放回抽样组合)
combinations_with_replacement 组合有重复 (有放回抽样组合)
defcombinationSum3(self, k:int, n:int)-> List[List[int]]:return[list(i)for i in itertools.combinations(range(1,10), k)ifsum(i)== n]
defsolve(self, board: List[List[str]])->None:"""
Do not return anything, modify board in-place instead.
"""ifnot board:return
n, m =len(board),len(board[0])defdfs(x, y ):ifnot0<= x < n ornot0<= y < m or board[x][y]!='O':return
board[x][y]='A'
dfs(x +1,y)
dfs(x -1,y)
dfs(x, y +1)
dfs(x, y -1)for i inrange(n):
dfs(i,0)
dfs(i, m -1)for i inrange(m -1):
dfs(0, i)
dfs(n -1, i)for i inrange(n):for j inrange(m):if board[i][j]=='A':
board[i][j]='O'elif board[i][j]=='O':
board[i][j]='X'
defnumIslands(self, grid: List[List[str]])->int:
nr =len(grid)if nr ==0:return0
nc =len(grid[0])
num_islands =0for r inrange(nr):for c inrange(nc):if grid[r][c]=='1':
num_islands +=1
grid[r][c]='0'
neighbors = collections.deque([(r, c)])while neighbors:
row, col = neighbors.popleft()for x, y in[(row -1, col),(row +1, col),(row, col -1),(row, col +1)]:if0<= x < nr and0<= y < nc and grid[x][y]=='1':
neighbors.append((x, y))
grid[x][y]='0'return num_islands
deffindWords(self, board: List[List[str]], words: List[str])-> List[str]:ifnot board ornot board[0]:return[]ifnot words:return[]
self.result =set()
root = collections.defaultdict()for word in words:
node = root
for char in word:
node = node.setdefault(char,collections.defaultdict())
node[END_OF_WORD]= END_OF_WORD
self.m, self.n =len(board),len(board[0])for i inrange(self.m):for j inrange(self.n):if board[i][j]in root:
self._dfs(board,i,j,"",root)returnlist(self.result)def_dfs(self, board, i, j,cur_word, cur_dict):
cur_word += board[i][j]
cur_dict = cur_dict[board[i][j]]if END_OF_WORD in cur_dict:
self.result.add(cur_word)
tmp,board[i][j]= board[i][j],'@'for k inrange(4):
x, y= i + dx[k],j + dy[k]if0<=x < self.m and0<=y<self.n and board[x][y]!='@'and board[x][y]in cur_dict:
self._dfs(board,x,y,cur_word,cur_dict)
board[i][j]= tmp
# 方法一:使用前缀树的回溯deffindWords(self, board: List[List[str]], words: List[str])-> List[str]:
WORD_KEY ='$'
trie ={}for word in words:
node = trie
for letter in word:# retrieve the next node; If not found, create a empty node.
node = node.setdefault(letter,{})# mark the existence of a word in trie node
node[WORD_KEY]= word
rowNum =len(board)
colNum =len(board[0])
matchedWords =[]defbacktracking(row, col, parent):
letter = board[row][col]
currNode = parent[letter]# check if we find a match of word
word_match = currNode.pop(WORD_KEY,False)if word_match:# also we removed the matched word to avoid duplicates,# as well as avoiding using set() for results.
matchedWords.append(word_match)# Before the EXPLORATION, mark the cell as visited
board[row][col]='#'# Explore the neighbors in 4 directions, i.e. up, right, down, leftfor(rowOffset, colOffset)in[(-1,0),(0,1),(1,0),(0,-1)]:
newRow, newCol = row + rowOffset, col + colOffset
if newRow <0or newRow >= rowNum or newCol <0or newCol >= colNum:continueifnot board[newRow][newCol]in currNode:continue
backtracking(newRow, newCol, currNode)# End of EXPLORATION, we restore the cell
board[row][col]= letter
# Optimization: incrementally remove the matched leaf node in Trie.ifnot currNode:
parent.pop(letter)for row inrange(rowNum):for col inrange(colNum):# starting from each of the cellsif board[row][col]in trie:
backtracking(row, col, trie)return matchedWords
链接:https://leetcode-cn.com/problems/word-search-ii/solution/dan-ci-sou-suo-ii-by-leetcode/
"""
class Node:
def __init__(self, val = 0, neighbors = None):
self.val = val
self.neighbors = neighbors if neighbors is not None else []
"""classSolution:def__init__(self):
self.visited ={}defcloneGraph(self, node:'Node')->'Node':ifnot node:return node
if node in self.visited:return self.visited[node]
clone_node = Node(node.val,[])
self.visited[node]= clone_node
if node.neighbors:
clone_node.neighbors =[self.cloneGraph(n)for n in node.neighbors]return clone_node
defcanFinish(self, numCourses:int, prerequisites: List[List[int]])->bool:
edges = collections.defaultdict(list)
indegrees =[0]* numCourses
for info in prerequisites:
edges[info[1]].append(info[0])
indegrees[info[0]]+=1
q = collections.deque([u for u inrange(numCourses)if indegrees[u]==0])
visited =0while q:
visited +=1
u = q.popleft()for v in edges[u]:
indegrees[v]-=1if indegrees[v]==0:
q.append(v)return visited == numCourses
defcanCompleteCircuit(self, gas, cost):ifsum(gas)<sum(cost):return-1
total = start =0for i inrange(len(gas)):
total += gas[i]- cost[i]if total <0:
total =0
start = i +1return start
# 暴力defcanCompleteCircuit(self, gas, cost):ifsum(gas)<sum(cost):return-1
ln =len(gas)for i inrange(ln):if gas[i]< cost[i]:continue
total =0for j inrange(i, i + ln):
j %= ln
total += gas[j]- cost[j]if total <0:breakelse:return i
return-1
deflengthOfLongestSubstring(self, s:str)->int:
cache ={}
left = maxlen=0for i, j inenumerate(s):if j in cache:
left =max(left, cache[j]+1)
cache[j]= i
maxlen =max(maxlen, i - left +1)return maxlen
defmaxArea(self, height: List[int])->int:
ans =0
n =len(height)
left, right =0, n -1while left < right:
cur =min(height[right], height[left])*(right - left)
ans =max(ans, cur)if height[left]< height[right]:
left +=1else:
right -=1return ans
defthreeSum(self, nums: List[int])-> List[List[int]]:
res =[]
nums.sort()for i inrange(len(nums)-2):if i >0and nums[i]== nums[i -1]:continue
l, r = i +1,len(nums)-1while l < r:
s = nums[i]+ nums[l]+ nums[r]if s <0: l +=1elif s >0: r -=1else:
res.append((nums[i], nums[l], nums[r]))while l < r and nums[l]== nums[l +1]:
l +=1while l < r and nums[r]== nums[r -1]:
r -=1
l +=1;r -=1return res
defthreeSumClosest(self, nums: List[int], target:int)->int:
nums.sort()
n =len(nums)
best =10**7# 根据差值的绝对值来更新答案defupdate(cur):nonlocal best
ifabs(cur - target)<abs(best - target):
best = cur
# 枚举 afor i inrange(n):# 保证和上一次枚举的元素不相等if i >0and nums[i]== nums[i -1]:continue# 使用双指针枚举 b 和 c
j, k = i +1, n -1while j < k:
s = nums[i]+ nums[j]+ nums[k]# 如果和为 target 直接返回答案if s == target:return target
update(s)if s > target:# 如果和大于 target,移动 c 对应的指针
k0 = k -1# 移动到下一个不相等的元素while j < k0 and nums[k0]== nums[k]:
k0 -=1
k = k0
else:# 如果和小于 target,移动 b 对应的指针
j0 = j +1# 移动到下一个不相等的元素while j0 < k and nums[j0]== nums[j]:
j0 +=1
j = j0
return best
defremoveDuplicates(self, nums: List[int])->int:# 变动1: 由于元素可以重复2次,left现在从第二个元素开始,right从第三个元素开始
left =1for right inrange(2,len(nums)):# 变动2: 以前之和nums[left]比, 现在还要和nums[left - 1]比,从而保证元素可以重复两次if nums[right]== nums[left]and nums[right]== nums[left -1]:continue
left +=1
nums[left]= nums[right]return left +1# 至多K次defremoveDuplicates(self, nums: List[int], K:int)->int:
left = K -1for right inrange(K,len(nums)):
tag =Truefor i inrange(K):
tag *= nums[right]== nums[left - i]if tag:continue
left +=1
nums[left]= nums[right]return left +1
defminSubArrayLen(self, s:int, nums: List[int])->int:ifnot nums:return0
n =len(nums)
ans = n +1
start, end =0,0
total =0while end < n:
total += nums[end]while total >= s:
ans =min(ans, end - start +1)
total -= nums[start]
start +=1
end +=1return0if ans == n +1else ans
# 方法二:前缀和 + 二分查找defminSubArrayLen(self, s:int, nums: List[int])->int:ifnot nums:return0
n =len(nums)
ans = n +1
sums =[0]for i inrange(n):
sums.append(sums[-1]+ nums[i])for i inrange(1, n +1):
target = s + sums[i -1]
bound = bisect.bisect_left(sums, target)if bound !=len(sums):
ans =min(ans, bound -(i -1))return0if ans == n +1else ans
deffindSubstring(self, s:str, words: List[str])-> List[int]:
allWords = collections.Counter(words)
wordNum =len(words)
wordLen =len(words[0])
res =[]for i inrange(len(s)- wordNum * wordLen +1):
subWords = collections.defaultdict(int)
index = i
while index < i + wordNum * wordLen:
curWord = s[index: index + wordLen]if curWord notin allWords or subWords[curWord]== allWords[curWord]:break
subWords[curWord]+=1
index += wordLen
if index == i + wordNum * wordLen:
res.append(i)return res
deffindSubstring(self, s:str, words: List[str])-> List[int]:from collections import Counter
ifnot s ornot words:return[]
one_word =len(words[0])
word_num =len(words)
n =len(s)if n < one_word:return[]
words = Counter(words)
res =[]for i inrange(0, one_word):
cur_cnt =0
left = i
right = i
cur_Counter = Counter()while right + one_word <= n:
w = s[right:right + one_word]
right += one_word
if w notin words:
left = right
cur_Counter.clear()
cur_cnt =0else:
cur_Counter[w]+=1
cur_cnt +=1while cur_Counter[w]> words[w]:
left_w = s[left:left+one_word]
left += one_word
cur_Counter[left_w]-=1
cur_cnt -=1if cur_cnt == word_num :
res.append(left)return res
defcountAndSay(self, n:int)->str:
pre =''
cur ='1'# 从第 2 项开始for _ inrange(1, n):# 这里注意要将 cur 赋值给 pre# 因为当前项,就是下一项的前一项。有点绕,尝试理解下
pre = cur
# 这里 cur 初始化为空,重新拼接
cur =''# 定义双指针 start,end
start =0
end =0# 开始遍历前一项,开始描述while end <len(pre):# 统计重复元素的次数,出现不同元素时,停止# 记录出现的次数,while end <len(pre)and pre[start]== pre[end]:
end +=1# 元素出现次数与元素进行拼接
cur +=str(end-start)+ pre[start]# 这里更新 start,开始记录下一个元素
start = end
return cur
deflengthOfLongestSubstringTwoDistinct(self, s:str)->int:
n =len(s)if n <3:return n
left, right =0,0
hashmap = collections.defaultdict()
max_len =2while right <n:iflen(hashmap)<3:
hashmap[s[right]]= right
right +=1iflen(hashmap)==3:
del_idx =min(hashmap.values())del hashmap[s[del_idx]]
left = del_idx +1
max_len =max(max_len, right - left)return max_len
deftrap(self, height):
ans =0
stack =list()
n =len(height)
height =[0]+ height +[0]for i, h inenumerate(height):while stack and h > height[stack[-1]]:
top = stack.pop()ifnot stack:break
currHeigh =min(height[stack[-1]], height[i])- height[top]
ans +=(i - stack[-1]-1)* currHeigh
stack.append(i)return ans
deflargestRectangleArea(self, heights: List[int])->int:
stack =[]
heights =[0]+ heights +[0]
res =0for i, h inenumerate(heights):while stack and heights[stack[-1]]> h:
tmp = stack.pop()
res =max(res,(i - stack[-1]-1)* heights[tmp])
stack.append(i)return res
defmaximalRectangle(self, matrix: List[List[str]])->int:
res =0ifnot matrix ornot matrix[0]:return res
defhelper(arr):nonlocal res
stack =[]for i inrange(len(arr)):while stack and arr[i]< arr[stack[-1]]:
idx =stack.pop()
res =max(res,(i -stack[-1]-1)* arr[idx])
stack.append(i)
r, c =len(matrix),len(matrix[0])
cnts =[0]*(c +2)for i inrange(r):for j inrange(c):if matrix[i][j]=='1':
cnts[j +1]+=1else:
cnts[j+1]=0
helper(cnts)return res
defsearch(self, nums: List[int], target:int)->bool:ifnot nums:returnFalse
n =len(nums)if n ==1:return nums[0]== target
l, r =0, n -1while l <= r:
mid =(l + r)//2if nums[mid]== target:returnTrueif nums[l]== nums[mid]and nums[mid]== nums[r]:
l +=1
r -=1elif nums[l]<= nums[mid]:if nums[l]<= target and target <= nums[mid]:
r = mid -1else:
l = mid +1else:if nums[mid]< target and target <= nums[n -1]:
l = mid +1else:
r = mid -1returnFalse
import bisect
classSolution:defsearchRange(self, nums, target):
left = bisect.bisect_left(nums,target)if left ==len(nums)or nums[left]!= target:return[-1,-1]
right = bisect.bisect_right(nums,target)return[left,right -1]classSolution:defsearchRange(self, nums, target):defbisect_left(num):
left, right =0,len(nums)-1while left <= right:
mid =(left + right)//2if num <= nums[mid]:
right = mid -1else:
left = mid +1return left
begin = bisect_left(target)if begin ==len(nums)or nums[begin]!= target:return[-1,-1]return[begin, bisect_left(target +1)-1]
defsearchMatrix(self, matrix, target):
M, N =len(matrix),len(matrix[0])
left, right =0, M * N -1while left <= right:
mid = left +(right - left)//2
cur = matrix[mid // N][mid % N]if cur == target:returnTrueelif cur < target:
left = mid +1else:
right = mid -1returnFalse
defsplitArray(self, nums: List[int], m:int)->int:defcheck(x):
total, cnt =0,1for num in nums:if total + num > x:
cnt +=1
total = num
else:
total += num
return cnt <= m
left =max(nums)
right =sum(nums)while left < right:
mid =(left + right)//2if check(mid):
right = mid
else:
left = mid +1return left
definorderTraversal(self, root: TreeNode)-> List[int]:
ret =[]
res =[]ifnot root:return
res.append(root.val)
self.inorderTraversal(root.left)
self.inorderTraversal(root.right)print( res)return res
# 给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n # 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。# Definition for a binary tree node.# class TreeNode:# def __init__(self, val=0, left=None, right=None):# self.val = val# self.left = left# self.right = rightclassSolution:defgenerateTrees(self, n:int)-> List[TreeNode]:defgenerateTrees(start, end):if start > end:return[None,]
allTrees =[]for i inrange(start,end+1):
leftTrees = generateTrees(start, i -1)
rightTrees = generateTrees(i +1, end)for l in leftTrees:for r in rightTrees:
currTree = TreeNode(i)
currTree.left = l
currTree.right = r
allTrees.append(currTree)return allTrees
return generateTrees(1, n)if n else[]
# 给你一个整数 n ,求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二# 叉搜索树 有多少种?返回满足题意的二叉搜索树的种数。defnumTrees(self, n:int)->int:
C =1for i inrange(0, n):
C = C *2*(2* i +1)/(i +2)returnint(C)defnumTrees(self, n):"""
:type n: int
:rtype: int
"""
G =[0]*(n+1)
G[0], G[1]=1,1for i inrange(2, n+1):for j inrange(1, i+1):
G[i]+= G[j-1]* G[i-j]return G[n]
defrecoverTree(self, root: TreeNode)->None:
self.firstNode =None
self.secondNode =None
self.preNode = TreeNode(float('-inf'))
stack =[]
p = root
while stack or p:while p:
stack.append(p)
p = p.left
p = stack.pop()ifnot firstNode and pre.val > p.val:
firstNode = pre
if firstNode and pre.val > p.val:
secondNode = p
pre = p
p = p.right
firstNode.val, secondNode.val = secondNode.val, firstNode.val
# 线索二叉树defrecoverTree(self, root: TreeNode)->None:
x, y, pre, tmp =None,None,None,Nonewhile root:if root.left:
tmp = root.left
while tmp.right and tmp.right != root:
tmp = tmp.right
if tmp.right isNone:# 建立线索
tmp.right = root
root = root.left
else:if pre and pre.val > root.val:
y = root
ifnot x:
x = pre
pre = root
tmp.right =None# 拆除线索
root = root.right
else:if pre and pre.val > root.val:
y = root
ifnot x:
x = pre
pre = root
root = root.right
if x and y:
x.val, y.val = y.val, x.val
defverticalTraversal(self, root):
seen = collections.defaultdict(lambda: collections.defaultdict(list))defdfs(node, x=0, y=0):if node:
seen[x][y].append(node)
dfs(node.left, x-1, y+1)
dfs(node.right, x+1, y+1)
dfs(root)
ans =[]for x insorted(seen):
report =[]for y insorted(seen[x]):
report.extend(sorted(node.val for node in seen[x][y]))
ans.append(report)return ans
deflowestCommonAncestor(self, root:'TreeNode', p:'TreeNode', q:'TreeNode')->'TreeNode':ifnot root or root ==p or root ==q :return root
left = self.lowestCommonAncestor(root.left,p,q)
right = self.lowestCommonAncestor(root.right,p,q)ifnot left:return right
ifnot right:return left
return root
defflatten(self, root: TreeNode)->None:"""
Do not return anything, modify root in-place instead.
"""
cur = root
while cur:if cur.left:
pre = nxt = cur.left
while pre.right:
pre = pre.right
pre.right = cur.right
cur.left =None
cur.right = nxt
cur = cur.right
# Definition for singly-linked list.# class ListNode:# def __init__(self, val=0, next=None):# self.val = val# self.next = nextclassSolution:defaddTwoNumbers(self, l1: ListNode, l2: ListNode)-> ListNode:
current = dummy = ListNode()
carry, value =0,0while carry or l1 or l2:
value = carry
if l1: l1, value = l1.next, l1.val + value
if l2: l2, value = l2.next, l2.val + value
carry, value =divmod(value,10)
current.next= ListNode(value)
current = current.nextreturn dummy.next
classSolution:defremoveNthFromEnd(self, head: ListNode, n:int)-> ListNode:
dummy = ListNode(0)
dummy.next= head
fast = head
slow = dummy
while n-1>0and fast:
fast = fast.next
n -=1if n >1:return[]while fast and fast.next:
slow = slow.next
fast = fast.next
slow.next= slow.next.nextreturn dummy.next
# 归并排序(递归法)defsortList(self, head: ListNode)-> ListNode:ifnot head ornot head.next:return head # termination.# cut the LinkedList at the mid index.
slow, fast = head, head.nextwhile fast and fast.next:
fast, slow = fast.next.next, slow.next
mid, slow.next= slow.next,None# save and cut.# recursive for cutting.
left, right = self.sortList(head), self.sortList(mid)# merge `left` and `right` linked list and return it.
h = res = ListNode(0)while left and right:if left.val < right.val: h.next, left = left, left.nextelse: h.next, right = right, right.next
h = h.next
h.next= left if left else right
return res.next# 归并排序(从底至顶直接合并)defsortList(self, head: ListNode)-> ListNode:
h, length, intv = head,0,1while h: h, length = h.next, length +1
res = ListNode(0)
res.next= head
# merge the list in different intv.while intv < length:
pre, h = res, res.nextwhile h:# get the two merge head `h1`, `h2`
h1, i = h, intv
while i and h: h, i = h.next, i -1if i:break# no need to merge because the `h2` is None.
h2, i = h, intv
while i and h: h, i = h.next, i -1
c1, c2 = intv, intv - i # the `c2`: length of `h2` can be small than the `intv`.# merge the `h1` and `h2`.while c1 and c2:if h1.val < h2.val: pre.next, h1, c1 = h1, h1.next, c1 -1else: pre.next, h2, c2 = h2, h2.next, c2 -1
pre = pre.next
pre.next= h1 if c1 else h2
while c1 >0or c2 >0: pre, c1, c2 = pre.next, c1 -1, c2 -1
pre.next= h
intv *=2return res.next
'''
给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。
'''# 双链表合并defpartition(self, head, x):ifnot head:return head
small = ListNode()
sm = small
large = ListNode()
lg = large
while head:if head.val < x:
sm.next= head
sm = sm.nextelse:
lg.next= head
lg = lg.next
head = head.next
lg.next=None
sm.next= large.nextreturn small.next# 寻找第一个large链表头 defpartition(self, head, x):
tmp = ret = ListNode()
li = head
ins =Nonewhile li:if li.val < x:
tmp.next= li
tmp = tmp.next
li = li.nextelse:
ins = li
breakwhile li and li.next:if li.next.val < x:
tmp.next= li.next
tmp = li.next
li.next= li.next.nextelse:
li = li.next
tmp.next= ins
return ret.next
defcalculate(self, s:str)->int:
ops =[1]
sign =1
ret =0
n =len(s)
i =0while i < n:if s[i]==' ':
i +=1elif s[i]=='+':
sign = ops[-1]
i +=1elif s[i]=='-':
sign =-ops[-1]
i+=1elif s[i]=='(':
ops.append(sign)
i +=1elif s[i]==')':
ops.pop()
i +=1else:
num =0while i < n and s[i].isdigit():
num = num *10+ord(s[i])-ord('0')
i +=1
ret += num * sign
return ret
defisValid(self, s):
stack =[]
paren_map ={')':'(',']':'[','}':'{'}for c in s:if c notin paren_map:
stack.append(c)elifnot stack or paren_map[c]!=stack.pop():returnFalsereturnnot stack
defsimplifyPath(self, path):
stack =[]for p in path.split('/'):if p notin['.','..','']:
stack.append(p)elif p =='..'and stack:
stack.pop()return f"/{'/'.join(stack)}"
defrotate(self, matrix: List[List[int]])->None:"""
Do not return anything, modify matrix in-place instead.
"""
matrix[:]=[list(t)[::-1]for t inzip(*matrix)]
defgenerateMatrix(self, n:int)-> List[List[int]]:
l, r, t, b =0, n -1,0, n -1
mat =[[0for _ inrange(n)]for _ inrange(n)]
num, tar =1, n * n
while num <= tar:for i inrange(l, r +1):
mat[t][i]= num
num +=1
t +=1for i inrange(t,b +1):
mat[i][r]= num
num +=1
r -=1for i inrange(r, l-1,-1):
mat[b][i]= num
num +=1
b -=1for i inrange(b, t -1,-1):
mat[i][l]= num
num +=1
l +=1return mat
defconvert(self, s:str, numRows:int)->str:if numRows ==1:return s
rows =[""]* numRows
n =2* numRows -2for i, char inenumerate(s):
x = i % n
rows[min(x, n - x)]+= char
return"".join(rows)
classSolution:
VALUE_SYMBOLS =[(1000,"M"),(900,"CM"),(500,"D"),(400,"CD"),(100,"C"),(90,"XC"),(50,"L"),(40,"XL"),(10,"X"),(9,"IX"),(5,"V"),(4,"IV"),(1,"I")]defintToRoman(self, num:int)->str:
roman =list()for value, symbol in Solution.VALUE_SYMBOLS:while num >= value:
num -= value
roman.append(symbol)if num ==0:breakreturn''.join(roman)
classSolution:
SYMBOL_VALUES ={'I':1,'V':5,'X':10,'L':50,'C':100,'D':500,'M':1000,}defromanToInt(self, s:str)->int:
ans =0
n =len(s)for i, ch inenumerate(s):
value = Solution.SYMBOL_VALUES[ch]if i < n -1and value < Solution.SYMBOL_VALUES[s[i+1]]:
ans -= value
else:
ans += value
return ans
defisNumber(self, s:str)->bool:# DFA transitions: dict[action] -> successor
states =[{},# state 1{"blank":1,"sign":2,"digit":3,"dot":4},# state 2{"digit":3,"dot":4},# state 3{"digit":3,"dot":5,"e|E":6,"blank":9},# state 4{"digit":5},# state 5{"digit":5,"e|E":6,"blank":9},# state 6{"sign":7,"digit":8},# state 7{"digit":8},# state 8{"digit":8,"blank":9},# state 9{"blank":9}]defstrToAction(st):if'0'<= st <='9':return"digit"if st in"+-":return"sign"if st in"eE":return"e|E"if st =='.':return"dot"if st ==' ':return"blank"returnNone
currState =1for c in s:
action = strToAction(c)if action notin states[currState]:returnFalse
currState = states[currState][action]# ending states: 3,5,8,9return currState in{3,5,8,9}# pattern("[+-]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[Ee][+-]?\\d+)?")
deffullJustify(self, words: List[str], maxWidth:int)-> List[str]:
res =[]
n =len(words)
i =0defone_row_words(i):# 至少 一行能放下一个单词, cur_row_len
left = i
cur_row_len =len(words[i])
i +=1while i < n:# 当目前行 加上一个单词长度 再加一个空格if cur_row_len +len(words[i])+1> maxWidth:break
cur_row_len +=len(words[i])+1
i +=1return left, i
while i < n:
left, i = one_row_words(i)# 该行几个单词获取
one_row = words[left:i]# 如果是最后一行了if i == n :
res.append(" ".join(one_row).ljust(maxWidth," "))break# 所有单词的长度
all_word_len =sum(len(i)for i in one_row)# 至少空格个数
space_num = i - left -1# 可以为空格的位置
remain_space = maxWidth - all_word_len
# 单词之间至少几个空格,还剩几个空格没用if space_num:
a, b =divmod(remain_space, space_num)# print(a,b)# 该行字符串拼接
tmp =""for word in one_row:if tmp:
tmp +=" "* a
if b:
tmp +=" "
b -=1
tmp += word
#print(tmp, len(tmp))
res.append(tmp.ljust(maxWidth," "))return res
defisPalindrome(self, s:str)->bool:
sgood ="".join(ch.lower()for ch in s if ch.isalnum())return sgood == sgood[::-1]defisPalindrome(self, s:str)->bool:
sgood ="".join(ch.lower()for ch in s if ch.isalnum())
n =len(sgood)
left, right =0, n -1while left < right:if sgood[left]!= sgood[right]:returnFalse
left, right = left +1, right -1returnTrue
defread(self, buf, n):"""
:type buf: Destination buffer (List[str])
:type n: Number of characters to read (int)
:rtype: The number of actual characters read (int)
"""
bi =0for _ inrange(0, n,4):
temp =[None]*4
cur_len = read4(temp)for j inrange(cur_len):
buf[bi]= temp[j]
bi +=1returnmin(bi, n)
classSolution:def__init__(self):
self.buf =[]defread(self,buf,n):
buf_len =len(self.buf)iflen(self.buf)>= n:
buf[:n]= self.buf[:n]
self.buf = self.buf[n:]return n
cur = buf_len
while cur < n:
cache =['']*4
num = read4(cache)
self.buf +=cache[:num]
cur +=num
if num <4or n <=4:break
res =min(cur, n)
buf[:res]= self.buf[:res]
self.buf = self.buf[res:]return res
# 方法一:哈希表deffirstMissingPositive(self, nums: List[int])->int:
n =len(nums)for i inrange(n):if nums[i]<=0:
nums[i]= n +1for i inrange(n):
num =abs(nums[i])if num <= n:
nums[num -1]=-abs(nums[num -1])for i inrange(n):if nums[i]>0:return i +1return n +1# 方法二:置换deffirstMissingPositive(self, nums: List[int])->int:
n =len(nums)for i inrange(n):while1<= nums[i]<= n and nums[nums[i]-1]!= nums[i]:
nums[nums[i]-1], nums[i]= nums[i], nums[nums[i]-1]for i inrange(n):if nums[i]!= i +1:return i +1return n +1
# 方法一:哈希表defmajorityElement(self, nums: List[int])->int:
counts = collections.Counter(nums)returnmax(counts.keys(), key=counts.get)# 方法二:排序defmajorityElement(self, nums: List[int])->int:
nums.sort()return nums[len(nums)//2]# 方法三:随机化defmajorityElement(self, nums: List[int])->int:
majority_count =len(nums)//2whileTrue:
candidate = random.choice(nums)ifsum(1for elem in nums if elem == candidate)> majority_count:return candidate
# 方法四:分治defmajorityElement(self, nums: List[int])->int:defmajority_element_rec(lo, hi)->int:# base case; the only element in an array of size 1 is the majority# element.if lo == hi:return nums[lo]# recurse on left and right halves of this slice.
mid =(hi - lo)//2+ lo
left = majority_element_rec(lo, mid)
right = majority_element_rec(mid +1, hi)# if the two halves agree on the majority element, return it.if left == right:return left
# otherwise, count each element and return the "winner".
left_count =sum(1for i inrange(lo, hi +1)if nums[i]== left)
right_count =sum(1for i inrange(lo, hi +1)if nums[i]== right)return left if left_count > right_count else right
return majority_element_rec(0,len(nums)-1)# 方法五:Boyer-Moore 投票算法defmajorityElement(self, nums: List[int])->int:
count =0
candidate =Nonefor num in nums:if count ==0:
candidate = num
count +=(1if num == candidate else-1)return candidate
classTwoSum(object):def__init__(self):"""
Initialize your data structure here.
"""
self.num_counts ={}defadd(self, number):"""
Add the number to an internal data structure..
:type number: int
:rtype: None
"""if number in self.num_counts:
self.num_counts[number]+=1else:
self.num_counts[number]=1deffind(self, value):"""
Find if there exists any pair of numbers which sum is equal to the value.
:type value: int
:rtype: bool
"""for num in self.num_counts.keys():
comple = value - num
if num != comple:if comple in self.num_counts:returnTrueelif self.num_counts[num]>1:returnTruereturnFalse
deftitleToNumber(self, columnTitle:str)->int:
number, multiple =0,1for i inrange(len(columnTitle)-1,-1,-1):
k =ord(columnTitle[i])-ord("A")+1
number += k * multiple
multiple *=26return number
defhasCycle(self,head):
fast = slow= head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.nextif slow is fast:returnTruereturnFalsedefhasCycle(self,head:ListNode)->bool:
seen =set()while head:if head in seen:returnTrue
seen.add(head)
head = head.nextreturnFalse
defdetectCycle(self,head):
fast = slow= head
while slow and fast and fast.next:
slow = slow.next
fast = fast.next.nextif slow is fast:
ptr = head
while ptr isnot slow:
ptr,slow= ptr.next, slow.nextreturn ptr
returnNonedefdetectCycle(self, head: ListNode)->bool:
seen =set()while head:if head in seen:return head
seen.add(head)
head = head.nextreturnNone
defmaxPoints(self, points: List[List[int]])->int:
n =len(points)
ans =1for i inrange(n):
k_dict = collections.defaultdict(int)
max_count =0for j inrange(i +1, n):
x1 = points[i][0]
y1 = points[i][1]
x2 = points[j][0]
y2 = points[j][1]
a = x1 - x2
b = y1 - y2
k = self.gcd(a, b)
key =str(a // k)+'_'+str(b //k)
k_dict[key]+=1
max_count =max(max_count, k_dict[key])
ans =max(ans, max_count +1)return ans
defgcd(self, a, b):return a if b ==0else self.gcd(b, a % b)
defgetIntersectionNode(self, headA: ListNode, headB: ListNode)-> ListNode:
s =set()
p, q = headA, headB
while p:
s.add(p)
p = p.nextwhile q:if q in s:return q
q = q.nextreturnNone# 双指针defgetIntersectionNode(self, headA: ListNode, headB: ListNode)-> ListNode:
A, B = headA, headB
while A != B:
A = A.nextif A else headB
B = B.nextif B else headA
return A
defaddBinary(self, a, b)->str:
x, y =int(a,2),int(b,2)while y:
answer = x ^ y
carry =(x & y)<<1
x, y = answer, carry
returnbin(x)[2:]defaddBinary(self, a, b)->str:return'{0:b}'.format(int(a,2)+int(b,2))
defcandy(self, ratings: List[int])->int:
n =len(ratings)
left =[0]* n
for i inrange(n):if i >0and ratings[i]> ratings[i -1]:
left[i]= left[i -1]+1else:
left[i]=1
right = ret =0for i inrange(n -1,-1,-1):if i < n-1and ratings[i]> ratings[i +1]:
right +=1else:
right =1
ret +=max(left[i],right)return ret
deffindMissingRanges(self, nums: List[int], lower:int, upper:int)-> List[str]:
res =[]
low = lower -1
nums.append(upper +1)for num in nums:
dif = num -low
if dif ==2: res.append(str(low +1))elif dif >2:
res.append(str(low+1)+'->'+str(num -1))
low = num
return res
deflongestValidParentheses(self, s:str)->int:
left, right, res=0,0,0defone_direction(s,left, right, lp):nonlocal res
for i, ch inenumerate(s):if ch == lp:
left +=1else:
right +=1if left == right:
res =max(res,2* right)elif right > left:
left = right =0
one_direction(s, left, right,'(')
one_direction(s[::-1],left,right,')')return res
defmaximumGap(self, nums: List[int])->int:
n =len(nums)if n <2:return0
max_num =max(nums)
min_num =min(nums)
gap = math.ceil((max_num - min_num)/(n -1))
bucket =[[float("inf"),float("-inf")]for _ inrange(n -1)]#print(bucket)# 求出每个桶的最大值,和最小值for num in nums:if num == max_num or num == min_num:continue
loc =(num - min_num)// gap
bucket[loc][0]=min(num, bucket[loc][0])
bucket[loc][1]=max(num, bucket[loc][1])##print(bucket)# 遍历整个桶
preMin = min_num
res =float("-inf")for x, y in bucket:if x ==float("inf"):continue
res =max(res, x - preMin)
preMin = y
res =max(res, max_num - preMin)return res
defmaximumGap(self, nums: List[int])->int:
n =len(nums)if n <2:return0
res =0
nums.sort()for i inrange(1, n):
res =max(res, nums[i]- nums[i -1])return res
defgetPermutation(self, n:int, k:int)->str:
factorial =[1]for i inrange(1, n):
factorial.append(factorial[-1]* i)
k -=1
ans =list()
valid =[1]*(n +1)for i inrange(1, n +1):
order = k // factorial[n - i]+1for j inrange(1, n +1):
order -= valid[j]if order ==0:
ans.append(str(j))
valid[j]=0break
k %= factorial[n - i]return''.join(ans)
defnextPermutation(self, nums: List[int])->None:"""
Do not return anything, modify nums in-place instead.
"""iflen(nums)==1:return nums
n =len(nums)
left =-1
right = left +1for i inrange(1, n):if nums[i]>= nums[i-1]:
left = i
if nums[i]< nums[right]:
right = i
print(left)if left ==-1:for i inrange(0, n//2):
nums[i],nums[n -i-1]= nums[n -i-1], nums[i]else:
nums[left -1],nums[left]= nums[left], nums[left-1]
defcountDigitOne(self, n):"""
:type n: int
:rtype: int
"""if n <1:return0if n <10:return1# t需要能被10整除defcountPart(t):if t ==10:return1
s = t/10return10* countPart(t/10)+ s
ans =0# 判断n是几位数,如n=388,l就是100
y =10while y <= n:
y *=10
l = y /10
subn = n % l
ans += self.countDigitOne(subn)
c = n / l
ans += c * countPart(l)+(l if c !=1else subn+1)# 这里要注意下以1开头的情况return ans
defplusOne(self, digits: List[int])-> List[int]:
num =int(''.join(list(map(str,digits))))+1returnlist(map(int,list(str(num))))defplusOne(self, digits: List[int])-> List[int]:
n =len(digits)-1
num =0for i in digits:if n ==-1:break
num += i*(10**n)
n -=1
m = num +1
final =list(str(m))returnlist(map(int,final))
# 返回杨辉三角的第k行defgetRow(self, rowIndex:int)-> List[int]:
res =[1]*(rowIndex +1)for i inrange(1, rowIndex +1):
res[i]= res[i -1]*(rowIndex - i +1)// i
return res
# 方法一:做加法defmultiply(self, num1:str, num2:str)->str:if num1 =="0"or num2 =="0":return"0"
ans ="0"
m, n =len(num1),len(num2)for i inrange(n -1,-1,-1):
add =0
y =int(num2[i])
curr =["0"]*(n - i -1)for j inrange(m -1,-1,-1):
product =int(num1[j])* y + add
curr.append(str(product %10))
add = product //10if add >0:
curr.append(str(add))
curr ="".join(curr[::-1])
ans = self.addStrings(ans, curr)return ans
defaddStrings(self, num1:str, num2:str)->str:
i, j =len(num1)-1,len(num2)-1
add =0
ans =list()while i >=0or j >=0or add !=0:
x =int(num1[i])if i >=0else0
y =int(num2[j])if j >=0else0
result = x + y + add
ans.append(str(result %10))
add = result //10
i -=1
j -=1return"".join(ans[::-1])# 方法二:做乘法defmultiply(self, num1:str, num2:str)->str:if num1 =="0"or num2 =="0":return"0"
m, n =len(num1),len(num2)
ansArr =[0]*(m + n)for i inrange(m -1,-1,-1):
x =int(num1[i])for j inrange(n -1,-1,-1):
ansArr[i + j +1]+= x *int(num2[j])for i inrange(m + n -1,0,-1):
ansArr[i -1]+= ansArr[i]//10
ansArr[i]%=10
index =1if ansArr[0]==0else0
ans ="".join(str(x)for x in ansArr[index:])return ans