你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。
首先找到中间位置数据作为根节点,然后左边数组构建左子树,右边数组构建右子树,
通过递归调用就能实现
# 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 = right
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return
n = len(nums)
mid = n//2
root = TreeNode(val=nums[mid])
root.left = self.sortedArrayToBST(nums[:mid])
root.right = self.sortedArrayToBST(nums[mid+1:])
return root
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左
子树
只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
class Solution:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
def isValidBSTnode(node,low=float('-inf'),high=float('inf')):
if not node:
return True
val = node.val
if val<low or val>high:
return False
return isValidBSTnode(node.left,low,val) and isValidBSTnode(node.right,val,high)
return isValidBSTnode(root)
题目:给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
思路:根据preorder[0]找到根节点的数值,然后根据inorder确定根节点的位置,最后就可以知道两个数组中左右子树的索引。通过递归构建树
知识点
#获取inorder数组中数值root_val的index
index_in_inorder = inorder.index(root_val)
index_in_inorder就是左子树的长度
# 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 = right
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
def buildTreesub(preorder,inorder):
if not preorder or not inorder:
return
rootval = preorder[0]
node = TreeNode(val=rootval)
index_in_inorder = inorder.index(rootval)
node.left = buildTreesub(preorder[1:index_in_inorder+1],inorder[:index_in_inorder])
node.right = buildTreesub(preorder[index_in_inorder+1:],inorder[index_in_inorder+1:])
return node
res = buildTreesub(preorder,inorder)
return res
知识点
prefix_sums.get(current_sum, 0)意思是从prefix_sums字典中获取current_sum索引的值,如果没有该索引则返回0
强调文本 强调文本
加粗文本 加粗文本
标记文本
删除文本
引用文本
H2O is是液体。
210 运算结果是 1024.
回溯算法
注意
current_list[:] 添加list的时候是创建该list的副本,避免修改原始list,
class Solution:
def permute(self, nums: List[int]) -> List[List[int]]:
res = []
n=len(nums)
def backtrack(index,current_list):
if index==len(nums):
res.append(current_list[:])
for i in range(n):
if nums[i] not in current_list:
current_list.append(nums[i])
backtrack(index+1,current_list)
current_list.pop()
backtrack(0,[])
return res
题目:给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
思路:回溯法,遍历digit第一个数字的字母,添加到path中,然后调用回溯函数遍历下一个字母。边界条件:digit为空时,将结果添加到res中
注意:
return res if digits else []
假如digits为空,res是[‘’],因此这一段添加了条件判断
class Solution:
def letterCombinations(self, digits: str) -> List[str]:
string = ['abc','def','ghi','jkl','mno','pqrs','tuv','wxyz']
res = []
path = []
def backtracking(digits):
if not digits:
res.append(''.join(path))
return
index = int(digits[0])-2
for i in string[index]:
path.append(i)
backtracking(digits[1:])
path.pop()
backtracking(digits)
return res if digits else []
题目:给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 ,并以列表形式返回。你可以按 任意顺序 返回这些组合。
candidates 中的 同一个 数字可以 无限制重复被选取 。如果至少一个数字的被选数量不同,则两种组合是不同的。
对于给定的输入,保证和为 target 的不同组合数少于 150 个。
思路:从index之后尝试逐个添加元素到组合中,同时维护路径,判断有无达到目标值。
注意:candidates.sort()这段代码能提前剪枝,并且避免重复组合
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
n = len(candidates)
candidates.sort() #提前排序
path = []
def backtracking(target,index):
if 0 == target:
res.append(path.copy())
for i in range(index,n):
if candidates[i]>target:
return
path.append(candidates[i])
backtracking(target-candidates[i],i)
path.pop()
backtracking(target,0)
return res
题目:数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
思路:定义一个left和right维护左右括号的数量,当left数量小于n时,添加左括号,当right数量小于left时,添加右括号。
注意:string对象添加字符串是用"+"操作
class Solution:
def generateParenthesis(self, n: int) -> List[str]:
path = ""
res = []
def backtracking(path,left,right):
if len(path)==2*n:
res.append(path)
if left<n:
backtracking(path+'(',left+1,right)
if right<left:
backtracking(path+')',left,right+1)
backtracking("",0,0)
return res
题目:给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
思路:
定义一个dfs
通过i,j,k来维护matrix行,列和word元素索引,当i j超出边界或者matrx和word当前元素不匹配返回False;
当k为word最后一个索引则返回True;
标记matrix当前元素,获取下一个方向的结果res,回溯matrix当前元素,返回res
遍历matrix所有元素,如果有满足条件的情况则返回True,如果都没有则返回False
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m=len(board) #imax
n=len(board[0]) #jmax
def dfs(i,j,k):
if not 0<=i<=m-1 or not 0<=j<=n-1 or not word[k]==board[i][j]:
return False
if k==len(word)-1:
return True
board[i][j] = ''
res = dfs(i-1,j,k+1) or dfs(i+1,j,k+1) or dfs(i,j-1,k+1) or dfs(i,j+1,k+1)
board[i][j] = word[k]
return res
for i in range(m):
for j in range(n):
if dfs(i,j,0):
return True
return False
题目:给你一个字符串 s,请你将 s 分割成一些子串,使每个子串都是
回文串。返回 s 所有可能的分割方案。
思路:用start变量表示子串的初始位置,end表示子串的终止位置,判断s[start:end]字符串是否是回文字符串,如果是的话添加该子串到路径path中,然后继续对剩余子串进行同样的操作。
注意:添加结果是添加path.copy(),因为path是会变的,需要保存当前状态
class Solution:
def partition(self, s: str) -> List[List[str]]:
res = []
path = []
def isvalid(string):
return string==string[::-1]
def backtracking(start,path):
if start==len(s):
res.append(path.copy())
for end in range(start+1,len(s)+1):
if isvalid(s[start:end]):
path.append(s[start:end])
backtracking(end,path)
path.pop()
backtracking(0,[])
return res
题目:给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
思路:二分法查找
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left = 0
right = len(nums)-1
while left<=right:
m = (left+right)//2
if nums[m]==target:
return m
if nums[m]>=target:
right = m-1
else:
left = m+1
return left
题目:给你一个满足下述两条属性的 m x n 整数矩阵:
每行中的整数从左到右按非严格递增顺序排列。
每行的第一个整数大于前一行的最后一个整数。
给你一个整数 target ,如果 target 在矩阵中,返回 true ;否则,返回 false 。
思路:将每一行矩阵拼接在一起实际就是一个递增数组,因此可以直接用二分法搜索,当然实际中不需要拼接成数组,数组索引a[mid]到matrix的索引为matrix[mid//n][mid%n]
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
m = len(matrix) #imax
n = len(matrix[0]) # jmax
left = 0
right = m*n-1
while left<=right:
mid = (left+right)//2
val = matrix[mid//n][mid%n]
if val==target:
return True
elif val>target:
right=mid-1
else:
left=mid+1
return False
题目:给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
思路:哈希表+前缀和。定义current_sum表示当前节点到根节点路径的前缀和,通过哈希表维护前缀和出现的次数。通过predix_sum[current_sum-targetSum]获取前缀和为targetSum的路径总数。dfs所有节点就可更新所有路径总数。
注意:一定要初始化predix_sum[0]=1
生成哈希表的方式predix_sum = defalutdict(int)
# 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 = right
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
predix_sum = defaultdict(int)
predix_sum[0] = 1
def dfs(node,current_sum):
if not node:
return 0
current_sum+=node.val
count = predix_sum[current_sum-targetSum]
predix_sum[current_sum]+=1
count+=dfs(node.left,current_sum)
count+=dfs(node.right,current_sum)
predix_sum[current_sum]-=1
return count
return dfs(root,0)
题目:给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。
百度百科中最近公共祖先的定义为:“对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”
思路:找到从root到p和q的路径path_p path_q,然后对比两个路径的数值,最后一个一样的就是最近公共祖先
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
def findPath(node,target,path):
if not node:
return False
path.append(node)
if node==target:
return True
if findPath(node.left,target,path) or findPath(node.right,target,path):
return True
path.pop()#回溯,移除当前路径
return False
path_p,path_q = [],[]
findPath(root,p,path_p)
findPath(root,q,path_q)
i=0
while i<len(path_p) and i<len(path_q) and path_p[i]==path_q[i]:
i+=1
return path_p[i-1]
题目:给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
思路:把访问过的岛屿“插旗”。
class Solution:
def numIslands(self, grid: List[List[str]]) -> int:
m = len(grid)
n=len(grid[0])
def dfs(i,j):
if not 0<=i<=m-1 or not 0<=j<=n-1 or not grid[i][j]=="1":
return
grid[i][j] = "2"
dfs(i+1,j)
dfs(i-1,j)
dfs(i,j+1)
dfs(i,j-1)
count=0
for i in range(m):
for j in range(n):
if grid[i][j]=="1":
dfs(i,j)
count+=1
return count
题目:在给定的 m x n 网格 grid 中,每个单元格可以有以下三个值之一:
值 0 代表空单元格;
值 1 代表新鲜橘子;
值 2 代表腐烂的橘子。
每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1 。
思路:将腐烂的橘子位置添加到队列里面,通过深度优先遍历不断更新队列直到队列为空。
class Solution:
def orangesRotting(self, grid: List[List[int]]) -> int:
m, n ,time = len(grid), len(grid[0]), 0
direction = [(1,0),(-1,0),(0,1),(0,-1)]
queue = deque()
for i in range(m):
for j in range(n):
if grid[i][j]==2:
queue.append((i,j,time))
while queue:
i,j,time = queue.popleft()
for di,dj in direction:
inew,jnew = i+di,j+dj
if 0<=inew<=m-1 and 0<=jnew<=n-1 and grid[inew][jnew]==1:
grid[inew][jnew] = 2
queue.append((inew,jnew,time+1))
for row in grid:
for ele in row:
if ele==1:
return -1
return time
题目:你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。
在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。
例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false 。
思路:把数据看成一个图结构,使用拓扑排序解决该问题。
1、构建邻接矩阵
2、初始化每门课程的入度
3、将入度为0的课程加入队列中,弹出队列每门课程并将访问次数加1,然后将该课程的邻居入度减一,如果邻居入度为0则添加进队列,直至队列为空。
4、如果访问次数为课程数,则可能完成所有课程的学习。
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
adjcentlist = defaultdict(list)
indegree = [0]*numCourses
for first,second in prerequisites:
adjcentlist[second].append(first)
indegree[first]+=1
queue = deque([k for k in range(numCourses) if indegree[k]==0])
count = 0
while queue:
count+=1
vertex = queue.popleft()
print(vertex)
for neighboor in adjcentlist[vertex]:
indegree[neighboor]-=1
if indegree[neighboor]==0:
queue.append(neighboor)
if count==numCourses:
return True
else:
return False
题目:Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。
请你实现 Trie 类:
Trie() 初始化前缀树对象。
void insert(String word) 向前缀树中插入字符串 word 。
boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false 。
boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false 。
思路:创建一个Trinode类,childen表示其子节点,is_end表示该节点是否为末尾。
class Trinode:
def __init__(self):
self.childen = {}
self.is_end = False
class Trie:
def __init__(self):
self.root = Trinode()
def insert(self, word: str) -> None:
node = self.root
for string in word:
if string not in node.childen:
node.childen[string] = Trinode()
node = node.childen[string]
node.is_end = True
def search(self, word: str) -> bool:
node = self.root
for string in word:
if string not in node.childen:
return False
node = node.childen[string]
return node.is_end
def startsWith(self, prefix: str) -> bool:
node = self.root
for string in prefix:
if string not in node.childen:
return False
node = node.childen[string]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
题目:给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。
思路:二分法的变体
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
def searchRangeleft(nums,target):
n = len(nums)
left = 0
right = n-1
while left<=right:
mid = (left+right)//2
if nums[mid]<target:
left = mid+1
else:
right = mid-1
return left
n = len(nums)
i = searchRangeleft(nums,target)
j = searchRangeleft(nums,target+1)
j-=1
if i>=n or nums[i]!=target:
i = -1
if j<0 or nums[j]!=target:
j=-1
return [i,j]
题目:整数数组 nums 按升序排列,数组中的值 互不相同 。
在传递给函数之前,nums 在预先未知的某个下标 k(0 <= k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k+1], …, nums[n-1], nums[0], nums[1], …, nums[k-1]](下标 从 0 开始 计数)。例如, [0,1,2,4,5,6,7] 在下标 3 处经旋转后可能变为 [4,5,6,7,0,1,2] 。
给你 旋转后 的数组 nums 和一个整数 target ,如果 nums 中存在这个目标值 target ,则返回它的下标,否则返回 -1 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思路:对正常排序的情况采用二分法的移动指针方式,其它情况移动指针操作相反
class Solution:
def search(self, nums: List[int], target: int) -> int:
n = len(nums)
left,right = 0, n-1
while left<=right:
mid = (left+right)//2
if nums[mid]==target:
return mid
if nums[left]<=nums[mid]:
if nums[left]<=target<nums[mid]:
right = mid-1
else:
left = mid+1
else:
if nums[mid]<target<=nums[right]:
left = mid+1
else:
right = mid -1
return -1
题目:已知一个长度为 n 的数组,预先按照升序排列,经由 1 到 n 次 旋转 后,得到输入数组。例如,原数组 nums = [0,1,2,4,5,6,7] 在变化后可能得到:
若旋转 4 次,则可以得到 [4,5,6,7,0,1,2]
若旋转 7 次,则可以得到 [0,1,2,4,5,6,7]
注意,数组 [a[0], a[1], a[2], …, a[n-1]] 旋转一次 的结果为数组 [a[n-1], a[0], a[1], a[2], …, a[n-2]] 。
给你一个元素值 互不相同 的数组 nums ,它原来是一个升序排列的数组,并按上述情形进行了多次旋转。请你找出并返回数组中的 最小元素 。
你必须设计一个时间复杂度为 O(log n) 的算法解决此问题。
思路:二分法。初始化left和right指针,当nums[mid]>nums[right]说明最小值在mid右侧,此时更新left=mid+1, nums[mid]<=nums[right]说明最小值在mid或者mid左侧,此时更新right=mid,当left和right相等时就是最小值。
class Solution:
def findMin(self, nums: List[int]) -> int:
n = len(nums)
left, right = 0 , n-1
while left<right:
mid = (left+right)//2
if nums[mid]>nums[right]:
#最小值在右边
left = mid+1
else:
#最小值在左边或者mid
right = mid
return nums[left] #当left等于right时,就是结果
题目:给定一个只包括 ‘(’,‘)’,‘{’,‘}’,‘[’,‘]’ 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
每个右括号都有一个对应的相同类型的左括号。
思路:通过一个栈来存储左括号。
遍历所有字符,如果字符是左括号,则进栈,如果是右括号,当栈为空的时候或者出栈元素不匹配右括号,则返回False
最后栈是空则为True,否则为False
class Solution:
def isValid(self, s: str) -> bool:
stack = []
s_dict = {"}":"{",")":"(","]":"["}
left = ["(","[","{"]
for ele in s:
if ele in left:
stack.append(ele)
else:
if not stack or stack.pop()!=s_dict[ele]:
return False
return not stack
题目:设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
实现 MinStack 类:
MinStack() 初始化堆栈对象。
void push(int val) 将元素val推入堆栈。
void pop() 删除堆栈顶部的元素。
int top() 获取堆栈顶部的元素。
int getMin() 获取堆栈中的最小元素。
思路:构建一个栈用于存储所有元素,构建一个栈用于存储最小元素
class MinStack:
def __init__(self):
self.stack = []
self.stackmin = []
def push(self, val: int) -> None:
self.stack.append(val)
if not self.stackmin or val<=self.stackmin[-1]:
self.stackmin.append(val)
def pop(self) -> None:
if self.stack:
val=self.stack.pop()
if val==self.stackmin[-1]:
self.stackmin.pop()
def top(self) -> int:
if self.stack:
return self.stack[-1]
def getMin(self) -> int:
if self.stackmin:
return self.stackmin[-1]
# Your MinStack object will be instantiated and called as such:
# obj = MinStack()
# obj.push(val)
# obj.pop()
# param_3 = obj.top()
# param_4 = obj.getMin()
题目:给定一个整数数组 temperatures ,表示每天的温度,返回一个数组 answer ,其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。如果气温在这之后都不会升高,请在该位置用 0 来代替。
思路:单调栈
遍历每个数字
当栈非空且当前数字大于栈顶索引对应的数字时
则不断弹出栈顶索引,更新栈顶索引对应的答案
结束时将栈顶索引条件到单调栈中
遍历完成后,返回结果
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
n=len(temperatures)
ans = [0]*n
stack = []
for i in range(n):
while stack and temperatures[i]>temperatures[stack[-1]]:
prev_index = stack.pop()
ans[prev_index] = i - prev_index
stack.append(i)
return ans
题目:给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
思路:用一个前缀最小值存储索引i之前的最小值,用一个后缀最大值存储索引i之后的最大值,然后两个数组之差的最大值就是答案。
class Solution:
def maxProfit(self, prices: List[int]) -> int:
n = len(prices)
predix_min = [0]*n
predix_max = [0]*n
minp= prices[0]
maxp= prices[n-1]
for i in range(n):
minp = min(minp,prices[i])
maxp = max(maxp,prices[n-i-1])
predix_min[i] = minp
predix_max[n-i-1] = maxp
res = predix_max[0]-predix_min[0]
for i in range(n):
res = max(res,predix_max[i]-predix_min[i])
return res
题目:给你一个字符串 s 。我们要把这个字符串划分为尽可能多的片段,同一字母最多出现在一个片段中。
注意,划分结果需要满足:将所有划分结果按顺序连接,得到的字符串仍然是 s 。
返回一个表示每个字符串片段的长度的列表。
思路:贪心算法
第一次遍历得到所有字母出现的最后位置
定义start和end分别代表片段的开始和结束位置
第二次遍历,
更新end
当下标==end时,说明当前片段到头,计算当前片段的长度添加到答案中,并更新start
最后返回答案
class Solution:
def partitionLabels(self, s: str) -> List[int]:
last_index = {char:i for i, char in enumerate(s)}
res = []
start, end = 0,0
for i,char in enumerate(s):
end = max(end,last_index[char])
if i==end:
res.append(i-start+1)
start=end+1
return res
题目:假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
思路:用数组实现递归关系 dp[i]=dp[i-1]+dp[i-2]
注意:长度为1的时候直接返回结果,避免越界
class Solution:
def climbStairs(self, n: int) -> int:
if n==1:
return 1
res = [0]*n
res[0]=1
res[1]=2
for i in range(2,n):
res[i] = res[i-1]+res[i-2]
return res[n-1]
题目:给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
思路:动态规划
定义trangle保存最终结果
遍历每一层,构建一个长度为(len_row+1)的全1向量,然后处理中间的元素,动态规划关系为trangle[len_row][i]=trangle[len_row-1][i]+trangle[len_row-1][i-1]
返回trangle
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
trangle = []
for len_row in range(numRows):
tmp = [1]*(len_row+1)
trangle.append(tmp)
for i in range(1,len_row):
trangle[len_row][i]=trangle[len_row-1][i]+trangle[len_row-1][i-1]
return trangle
题目:
思路:动态规划,dp[i] = max(dp[i-1],dp[i-2]+nums[i])当前状态最大现金=max(前种状态最大现金,打劫当前现金+前前种状态最大现金)
class Solution:
def rob(self, nums: List[int]) -> int:
n = len(nums)
dp = [0]*n
if n==1:
return nums[0]
elif n==2:
return max(nums[0],nums[1])
dp[0] = nums[0]
dp[1] = max(nums[0],nums[1])
for i in range(2,n):
dp[i] = max(dp[i-1],dp[i-2]+nums[i])
return dp[n-1]
题目:给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
思路:动态规划,dp[i] = min(dp[i],1+dp[i-j*j])
class Solution:
def numSquares(self, n: int) -> int:
dp = [float("inf")]*(n+1)
dp[0] = 0
for i in range(n+1):
j=0
while j*j<=i:
dp[i] = min(dp[i],1+dp[i-j*j])
j+=1
return dp[n]
题目:给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续
子数组
(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
测试用例的答案是一个 32-位 整数。
思路:用max_current和min_current维护以当前索引数值为乘积的最大值和最小值,最小值要维护是因为最小值乘以负数会变最大值。
遍历数组所有数
用max_current和min_current维护以当前索引数值为乘积的最大值和最小值,更新答案res
返回res
class Solution:
def maxProduct(self, nums: List[int]) -> int:
maxnum = nums[0]
minnum = nums[0]
maxProduct = nums[0]
n=len(nums)
for i in range(1,n):
tmp_maxnum = max(nums[i],nums[i]*maxnum,nums[i]*minnum)
minnum = min(nums[i],nums[i]*maxnum,nums[i]*minnum)
maxnum = tmp_maxnum
maxProduct=max(maxProduct,maxnum)
return maxProduct
题目:给你一个 只包含正整数 的 非空 数组 nums 。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。
思路:动态规划
获取数组和,如果是奇数则返回False,是偶数则除以2得到target,此时的问题转化为数组元素和是否构成target,初始化dp状态转移数组,dp[i]表示数组里的元素是否可以构成i
遍历nums里每一个num
i从target到num遍历一遍,如果dp[i-num]为True说明i可以通过i-num和num两个数构建出来,因此dp[i]为True
返回dp[target]
class Solution:
def canPartition(self, nums: List[int]) -> bool:
sum_n = sum(nums)
if sum_n%2==1:
return False
target = int(sum_n/2)
dp = [False]*(target+1)
dp[0] = True
for num in nums:
for i in range(target,num-1,-1):
if dp[i-num]:
dp[i] = True
if dp[target]:
return True
return dp[target]
题目:给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
思路:动态规划dp[i] = min(dp[i],dp[i-coin]+1)
遍历所有的硬币,
遍历一遍dp,从coin开始,dp[i] = min(dp[i],dp[i-coin]+1)
如果dp[amount]不是无穷大返回dp[amount],否则返回-1
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
n = len(coins)
dp = [float("inf")]*(amount+1)
dp[0] = 0
for coin in coins:
for i in range(coin,amount+1):
dp[i] = min(dp[i],dp[i-coin]+1)
return dp[amount] if dp[amount]!=float("inf") else -1
#单词拆分
题目:
思路:动态规划,定义dp[i]表示s的前i个字符能否通过字典拼接,dp[0]=True表示空字符可以通过没有单词拼接
初始化dp
遍历所有字符下标i
遍历s[j:i],如果dp[j]为True,且s[j:i]在字典中,则dp[i]为True(s前j个字符可以通过单词拼接且s[j:i]在字典中)
返回结果
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n = len(s)
dp= [False]*(n+1)
dp[0] = True #0个字符,可以通过没有单词拼接到
for i in range(n+1):
for j in range(i):
if dp[j] and s[j:i] in wordDict:
dp[i] = True
return dp[n]
题目:一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
思路:动态规划,状态转移方程
dp[i][j] = dp[i-1][j]+dp[i][j-1]
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[0]*n for i in range(m)]
for i in range(n):
dp[0][i] = 1
for i in range(m):
dp[i][0] = 1
for i in range(1,m):
for j in range(1,n):
dp[i][j] = dp[i-1][j]+dp[i][j-1]
return dp[m-1][n-1]
题目:给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
思路:动态规划,状态转移方程
dp[i][j] = grid[i][j] + min(dp[i-1][j],dp[i][j-1])
注意:为了正确创造一个二维矩阵,需要正确格式,dp = [[0]*n for i in range(m)]
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
m = len(grid)
n = len(grid[0])
dp = [[0]*n for i in range(m)]
dp[0][0] = grid[0][0]
for i in range(1,m):
dp[i][0] = dp[i-1][0] + grid[i][0]
for j in range(1,n):
dp[0][j] = dp[0][j-1] + grid[0][j]
for i in range(1,m):
for j in range(1,n):
dp[i][j] = grid[i][j] + min(dp[i-1][j],dp[i][j-1])
return dp[m-1][n-1]
题目:给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
思路:使用 位运算 XOR 的特性 res = res^num
class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for num in nums:
res = res^num
return res
题目:给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地 对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。
我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。
必须在不使用库内置的 sort 函数的情况下解决这个问题。
思路:直接统计0 1 2的数量,然后重写nums
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
count = [0]*3
n=len(nums)
for num in nums:
count[num]+=1
for i in range(n):
if i<count[0]:
nums[i] = 0
elif count[0]<=i<count[0]+count[1]:
nums[i] =1
else:
nums[i]=2
return nums
题目:给你一个字符串 s,找到 s 中最长的
回文
子串
子字符串
子字符串 是字符串中连续的 非空 字符序列。
思路:动态规划
dp[i][j]表示s i到j中的字符串是否为回文字符串,因此如果首位字符串相等且中间字符串是回文字符串,则dp[i][j]也是回文字符串
class Solution:
def longestPalindrome(self, s: str) -> str:
n = len(s)
dp = [[False]*n for _ in range(n)]
if n<=1:
return s
max_len = 1
start = 0
for i in range(n):
dp[i][i] = True
for i in range(n-1):
if (s[i]==s[i+1]):
dp[i][i+1] = True
max_len = 2
start = i
for length in range(3,n+1):
#length从3到n
for i in range(n-length+1):
#i+length-1
j = i+length-1
if s[i]==s[j] and dp[i+1][j-1]:
dp[i][j] = True
max_len = length
start = i
return s[start:start+max_len]
题目:给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。
一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。
例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。
思路:动态规划,定义dp[i][j]为text1前i个字符和text2前j个字符的最长公共序列,那么递推关系为
if text1[i-1]==text2[j-1]:
dp[i][j] = 1 + dp[i-1][j-1]
else:
dp[i][j] = max(dp[i][j-1],dp[i-1][j])
注意:遍历的时候i j从1开始取值,取到m和n
class Solution:
def longestCommonSubsequence(self, text1: str, text2: str) -> int:
m = len(text1)
n = len(text2)
dp = [[0]*(n+1) for i in range(m+1)]
dp[0][0] = 0
for i in range(1,m+1):
for j in range(1,n+1):
if text1[i-1]==text2[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 dp[m][n]
题目:给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
思路:动态规划,定义dp[i][j]为word1前i个字符转成word2前j个字符的操作数量,动态规划关系为
if word1[i-1]==word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1+min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])
class Solution:
def minDistance(self, word1: str, word2: str) -> int:
m = len(word1)
n = len(word2)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(1,m+1):
#删除
dp[i][0] = i
for j in range(1,n+1):
#插入
dp[0][j] = j
for i in range(1,m+1):
for j in range(1,n+1):
if word1[i-1]==word2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = 1+min(dp[i-1][j-1],dp[i][j-1],dp[i-1][j])
return dp[m][n]
题目:给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为: k[encoded_string],表示其中方括号内部的 encoded_string 正好重复 k 次。注意 k 保证为正整数。
你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[4] 的输入。
思路:用一个栈存储当前的数字k和字符串current_string
遍历所有字符:
当字符为数字时,将字符串转化成数字并累加到临时变量k中
当字符为[时,将临时变量k和当前的字符串current_string添加到栈中,然后清空所有临时变量
当字符为]时,将栈顶元素弹出获取先前的字符串和数字,将当前字符串复制k次,接到先前字符串后面。
当字符为字母时,将字符添加到当前字符串中
最后返回的current_string就是答案。
注意:char.isdigit()函数就是判断char是否是数字的字符串
class Solution:
def decodeString(self, s: str) -> str:
stack = []
k = 0
current_string = ""
for char in s:
if char.isdigit():
k = k*10+int(char)
elif char=="[":
stack.append((current_string,k))
k=0
current_string=""
elif char=="]":
prev_string,num = stack.pop()
current_string = prev_string + current_string*num
else:
current_string = current_string+char
return current_string
class Solution:
def combinationSum(self, candidates: List[int], target: int) -> List[List[int]]:
res = []
n = len(candidates)
def dfs(start,current_combination,current_sum):
if current_sum==target:
res.append(list(current_combination))
return
elif current_sum>target:
return
for i in range(start,n):
current_combination.append(candidates[i])
dfs(i,current_combination,current_sum+candidates[i])
current_combination.pop()
dfs(0,[],0)
return res
旋转矩阵
定义四个方向
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m = len(matrix)
n = len(matrix[0])
top=0
bottom=m-1
left =0
right = n-1
res = [0](mn)
row, col = 0, 0
direction = [[0,1],[1,0],[0,-1],[-1,0]]
visited = [[False]*n for _ in range(m)]
direction_index = 0
for i in range(len(res)):
res[i] = matrix[row][col]
#print(row,col)
visited[row][col] = True
next_row , next_col = row+direction[direction_index][0], col + direction[direction_index][1]
if not (0<=next_row<=m-1 and 0<=next_col<=n-1 and not visited[next_row][next_col]):
direction_index = (direction_index+1)%4
row , col = row+direction[direction_index][0], col + direction[direction_index][1]
return res
旋转矩阵
先装置然后镜像
class Solution:
def rotate(self, matrix: List[List[int]]) -> None:
“”"
Do not return anything, modify matrix in-place instead.
“”"
rows = len(matrix)
cols = len(matrix[0])
def transpose(matrix,rows):
for i in range(rows):
for j in range(i+1):
#print(i,j)
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
return matrix
def minnor(matrix,rows):
for i in range(rows):
for j in range(0,int((rows+1)/2)):
matrix[i][j], matrix[i][rows-j-1] = matrix[i][rows-j-1], matrix[i][j]
return matrix
matrix = transpose(matrix,rows)
matrix = minnor(matrix,rows)
return matrix
搜索二维矩阵II
从右上角开始遍历
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
rows = len(matrix)
cols = len(matrix[0])
row , col = 0, cols-1
while row<=rows-1 and col>=0:
if target==matrix[row][col]:
return True
elif target>matrix[row][col]:
row+=1
elif target
相交链表
双指针同时走完两个链表,直到相交
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
h1 = headA
h2 = headB
while True:
if not h1 and not h2:
return
if not h1:
h1 = headB
if not h2:
h2 = headA
if h1==h2:
return h1
h1 = h1.next
h2 = h2.next
反转链表
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
current_node = head
res = None
while current_node:
next_node = current_node.next
current_node.next = res
res = current_node
current_node = next_node
return res
return res
判断回文链表
把链表的值存在数组上
class Solution:
def isPalindrome(self, head: Optional[ListNode]) -> bool:
temp = head
list_tmp = []
while temp:
list_tmp.append(temp.val)
temp = temp.next
middle = (len(list_tmp)+1)/2
n = len(list_tmp)
for i in range(int(middle)):
if list_tmp[i]==list_tmp[n-i-1]:
continue
else:
return False
return True
LRU缓存
双向链表,哈希表
class Listnode:
def init(self,key=0,value=0):
self.key=key
self.value=value
self.pre = None
self.next = None
class LRUCache:
def __init__(self, capacity: int):
self.capacity= capacity
self.cache={}
self.head = Listnode()
self.tail = Listnode()
self.head.next = self.tail
self.tail.prev = self.head
def remove(self,node):
prev_node = node.prev
next_node = node.next
prev_node.next = next_node
next_node.prev = prev_node
def add(self,node):
node.prev = self.head
node.next = self.head.next
self.head.next.prev = node
self.head.next =node
def get(self, key: int) -> int:
if key in self.cache:
node = self.cache[key]
self.remove(node)
self.add(node)
return node.value
else:
return -1
def put(self, key: int, value: int) -> None:
if key in self.cache:
node = self.cache[key]
self.remove(node)
else:
node = Listnode(key, value)
self.cache[key] = node
node.value = value
self.add(node)
if len(self.cache)>self.capacity:
tail_node = self.tail.prev
self.remove(tail_node)
del self.cache[tail_node.key]
中序遍历
递归
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
def traversal(node):
if node:
traversal(node.left)
result.append(node.val)
traversal(node.right)
traversal(root)
return result
二叉树最大深度
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
def maxDepthnode(node):
res=0
if node:
tmp =1+ max(maxDepthnode(node.right),maxDepthnode(node.left))
res = max(tmp,res)
return res
else:
return 0
return maxDepthnode(root)
翻转二叉树
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
def invertTreenode(node):
if node:
tmp = node.left
node.left=invertTreenode(node.right)
node.right=invertTreenode(tmp)
return node
else:
return
return invertTreenode(root)
对称二叉树
递归
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
def isSymmetricnode(l1,l2):
if not l1 and not l2:
return True
if not l1 or not l2:
return False
if l1.val==l2.val and isSymmetricnode(l1.left,l2.right) and isSymmetricnode(l1.right,l2.left):
return True
else:
return False
return isSymmetricnode(root.left,root.right)
二叉树的直径
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
self.res = 0
def dfs(node):
if node:
left_depth = dfs(node.left)
right_depth = dfs(node.right)
self.res = max(self.res,left_depth+right_depth)
return 1+max(left_depth,right_depth)
else:
return 0
dfs(root)
return self.res
二叉树展开为链表
class Solution:
def flatten(self, root: Optional[TreeNode]) -> None:
“”"
Do not return anything, modify root in-place instead.
“”"
if not root:
return
def dfs(node):
if not node:
return
#将左子树放到右子树
right_node = node.right
node.right = node.left
node.left = None
#将原右子树放当前右子树的末端
tmp = node
while tmp.right:
tmp = tmp.right
tmp.right = right_node
dfs(node.right)
dfs(root)
子集
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
n = len(nums)
res = []
def backtrace(start,current_com):
res.append(current_com[:])
for i in range(start,n):
current_com.append(nums[i])
backtrace(i+1,current_com)
current_com.pop()
backtrace(0,[])
return res
n = len(nums)
left,right = 0, n-1
while left<=right:
mid = (left+right)//2
if nums[left]<=nums[mid]:
if nums[left]<=target
class Solution:
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
d = defaultdict(list)
for s in strs:
d[‘’.join(sorted(s))].append(s) # sorted(s) 相同的字符串分到同一组
return list(d.values())
最长连续序列
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
nums = sorted(nums)
mx = 1
ans = 1
for i in range(len(nums)-1):
if nums[i]==nums[i+1]-1:
mx+=1
ans = max(mx,ans)
elif nums[i]==nums[i+1]:
continue
else:
mx = 1
return ans
移动0
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
“”"
Do not return anything, modify nums in-place instead.
“”"
count = 0
inz = 0
for i in range(len(nums)):
if nums[i] !=0:
nums[inz] = nums[i]
inz+=1
else:
count+=1
for i in range(count):
nums[len(nums)-i-1]=0
#print(nums)
return nums
最大容器
class Solution:
def maxArea(self, height: List[int]) -> int:
res =0
left = 0
right = len(height)-1
res = 0
while left
res = max(res,height[left](right-left))
left+=1
else:
res = max(res,height[right](right-left))
right-=1
return res
三数之和
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
res = []
n= len(nums)
for i in range(n-2):
if i>0 and nums[i]==nums[i-1]:
continue
left = i+1
right = n-1
while left0:
right-=1
return res
接雨水
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
left = 0
right = n-1
max_left = height[left]
max_right = height[right]
res = 0
while left=max_left:
max_left = height[left]
else:
res += max_left - height[left]
left+=1
else:
if height[right]>=max_right:
max_right = height[right]
else:
res+= max_right-height[right]
right-=1
return res
无重复字符串的最长子串
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
chatset = set()
left = 0
n = len(s)
res = 0
for right in range(n):
while s[right] in chatset:
chatset.remove(s[left])
left+=1
chatset.add(s[right])
res = max(res,right-left+1)
return res
找到字符串中的所有字母异位词
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
n_s = len(s)
n_p = len§
res = []
p_count = Counter§
for left in range(0,n_s-n_p+1):
ele_s = s[left:left+n_p]
s_count = Counter(ele_s)
if s_count==p_count:
res.append(left)
return res
统计给定整数数组 nums 中和为 k 的子数组的个数,使用前缀和与哈希表
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
n = len(nums)
current_sum = 0
prefix_sum = {0:1}
res = 0
for i in range(n):
current_sum+=nums[i]
if current_sum-k in prefix_sum:
res+= prefix_sum[current_sum-k]
#update the prefix_sum
if current_sum in prefix_sum:
prefix_sum[current_sum]+=1
else:
prefix_sum[current_sum] = 1
return res
滑动窗口最大值
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
res = []
n = len(nums)
if n==0:
return []
elif n==1:
return nums
dq = deque()
for i in range(k):
while dq and nums[i]>=nums[dq[-1]]:
dq.pop()
dq.append(i)
for i in range(k,n):
res.append(nums[dq[0]])
if dq and i-dq[0]>k-1:
dq.popleft()
while dq and nums[i]>=nums[dq[-1]]:
dq.pop()
dq.append(i)
res.append(nums[dq[0]])
return res
最大子数组和
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
max_current = nums[0]
max_global = nums[0]
n=len(nums)
for i in range(1,n):
max_current = max(max_current+nums[i],nums[i])
max_global = max(max_current,max_global)
return max_global
合并区间 排序
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key=lambda x: x[0])
res = [intervals[0]]
n = len(intervals)
for i in range(1,n):
interval = intervals[i]
if interval[0]<=res[-1][-1]:
res[-1][-1] = max(res[-1][-1],interval[-1])
else:
res.append(interval)
return res
轮转数组
容易出错的地方 k>n时情况不能忽视 k=k%n
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
“”"
Do not return anything, modify nums in-place instead.
“”"
n = len(nums)
k=k%n
res = []
for i in range(k-1,-1,-1):
res.append(nums[n-i-1])
for i in range(n-k):
res.append(nums[i])
nums[:] = res
return res
除自身以外数组的乘积 前缀法和后缀法
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [1]*n
left = 1
right = 1
for i in range(n):
res[i] = left
left*=nums[i]
for j in range(n-1,-1,-1):
res[j] *= right
right*= nums[j]
return res
找出最小正整数 将list转化成集合
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)
nums = set(nums)
for i in range(1,len(nums)+2):
if i not in nums:
return i
矩阵置0
暴力方法
class Solution:
def setZeroes(self, matrix: List[List[int]]) -> None:
“”"
Do not return anything, modify matrix in-place instead.
“”"
m = len(matrix)
n = len(matrix[0])
a = set()
b = set()
for i in range(m):
for j in range(n):
if matrix[i][j]==0:
a.add(i)
b.add(j)
for i in a:
for j in range(n):
matrix[i][j]=0
for j in b:
for i in range(m):
matrix[i][j]=0
return matrix
合并两个有序链表
递归法
class Solution:
def mergeTwoLists(self, list1: Optional[ListNode], list2: Optional[ListNode]) -> Optional[ListNode]:
if not list1:
return list2
if not list2:
return list1
if list1.val<=list2.val:
list1.next = self.mergeTwoLists(list1.next,list2)
return list1
else:
list2.next = self.mergeTwoLists(list1,list2.next)
return list2
两式相加
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
p = dummy
cn = 0
while (l1 or l2 or cn):
l1val = l1.val if l1 else 0
l2val = l2.val if l2 else 0
current_sum, cn = (l1val+l2val+cn)%10, (l1val+l2val+cn)//10
p.next = ListNode(current_sum)
p=p.next
l1 = l1.next if l1 else None
l2=l2.next if l2 else None
return dummy.next
删除链表的倒数第n个指针
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy_head = ListNode(0)
dummy_head.next = head
slow = dummy_head
fast = dummy_head
for i in range(n):
if not fast:
return head
fast = fast.next
while fast.next:
slow = slow.next
fast = fast.next
slow.next = slow.next.next
return dummy_head.next
两两交换链表当中的节点
class Solution:
def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
if not head.next:
return head
dummy_head = ListNode()
dummy_head.next = head
p = dummy_head
while head and head.next:
first = head
second = head.next
#swap
p.next = second
first.next = second.next
second.next = first
p = first
head=head.next
return dummy_head.next
二叉树直径
dfs
class Solution:
def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int:
self.res = 0
def dfs(node):
if node:
leftD=dfs(node.left)
rightD=dfs(node.right)
self.res = max(self.res,leftD+rightD)
return 1+max(leftD,rightD)
else:
return 0
dfs(root)
return self.res
层序遍历
deque([root]) # 初始化队列,根节点入队
queue.popleft() # 从队列中取出节点
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
if not root:
return []
res = []
init_queue = deque([root])
while init_queue:
n = len(init_queue)
current_res = []
for _ in range(n):
node = init_queue.popleft()
current_res.append(node.val)
if node.left:
init_queue.append(node.left)
if node.right:
init_queue.append(node.right)
res.append(current_res)
return res
将有序数组转化成二叉搜索树
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
if not nums:
return
n = len(nums)
mid = n//2
root = TreeNode(val=nums[mid])
root.left = self.sortedArrayToBST(nums[:mid])
root.right = self.sortedArrayToBST(nums[mid+1:])
return root