class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
# 动态规划
# dp[i][j]表示以matrix[i][j]为右下角的最大正方形边长
# 状态转移:dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
if len(matrix) == 0 or len(matrix[0]) == 0:
return 0
maxSide = 0
rows, columns = len(matrix), len(matrix[0])
dp = [[0] * columns for _ in range(rows)]
for i in range(rows):
for j in range(columns):
if matrix[i][j] == '1':
if i == 0 or j == 0:
dp[i][j] = 1
else:
dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
maxSide = max(maxSide, dp[i][j])
maxSquare = maxSide * maxSide
return maxSquare
# 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':
# 函数功能为给 p 或 q 找祖先
if not root or root == p or root == q:
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left:
return right
if not right:
return left
return root
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
# # 两个数组,分别存储 i 位置左侧数字和右侧数字的乘积
# n = len(nums)
# l = [1 for _ in range(n)]
# r = [1 for _ in range(n)]
# for i in range(1, n):
# l[i] = l[i-1] * nums[i-1]
# for i in range(n-2, -1, -1):
# r[i] = r[i+1] * nums[i+1]
# res = [0 for _ in range(n)]
# for i in range(n):
# res[i] = l[i] * r[i]
# return res
# O(1)时间复杂度,可以省去 r 数组,替换为一个值,动态更新
n = len(nums)
res = [1 for _ in range(n)]
r = 1 # 记录右侧数字乘积
for i in range(1, n):
res[i] = res[i-1] * nums[i-1]
for i in range(n-1, -1, -1):
res[i] = res[i] * r
r *= nums[i]
return res
单调队列
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
# # 优先级队列,时间复杂度 O(nlogn)
# n = len(nums)
# q = [(-nums[i], i) for i in range(k)] # 默认是最小堆
# heapq.heapify(q)
# res = [-q[0][0]]
# for i in range(k, n):
# heapq.heappush(q, (-nums[i], i))
# # 判断堆顶元素是否在窗口内
# while q[0][1] < i-k+1:
# heapq.heappop(q)
# # 更新 res
# res.append(-q[0][0])
# return res
# 单调队列
# 新加入元素如果比队尾元素大,就把比新加入元素小的都剔除,因为不可能是最大值了,新元素在后面
# 如果队首元素在窗口内,队首就是最大值
n = len(nums)
q = [] # 存储元素的索引,如果存储值的话,无法判断队首元素是否在窗口内
for i in range(k):
while q and nums[i] >= nums[q[-1]]:
q.pop(-1)
q.append(i)
res = [nums[q[0]]]
for i in range(k, n):
# 新元素入队
while q and nums[i] >= nums[q[-1]]:
q.pop(-1)
q.append(i)
# 判断队首元素是否在窗口内
while q[0] <= i - k:
q.pop(0)
res.append(nums[q[0]])
return res
class Solution:
def numSquares(self, n: int) -> int:
# 动态规划
# 状态转移:dp[i] = min(dp[i], dp[i - j*j] + 1)
dp = [float('inf') for _ in range(n+1)]
dp[0] = 0
dp[1] = 1
for i in range(2, n+1):
for j in range(1, int(i**0.5)+1):
dp[i] = min(dp[i], dp[i - j*j] + 1)
return dp[n]
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
# j = -1 # j标识第一个 0 的位置,与后面非 0 的数交换
# for i in range(len(nums)):
# if nums[i] == 0:
# if j == -1:
# j = i
# else:
# if j != -1:
# nums[i], nums[j] = nums[j], nums[i]
# j += 1
# 两个指针i和j
j = 0
for i in range(len(nums)):
# 当前元素!=0,就把其交换到左边,等于0的交换到右边,i 和 j 一起移动
# 如果是 0,j 不动,标识 0 的位置
if nums[i]:
nums[j],nums[i] = nums[i],nums[j]
j += 1
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
# 看做链表,如果存在重复数字,则链表中存在环
# 找到环的入口
fast = 0
slow = 0
while True:
fast = nums[nums[fast]]
slow = nums[slow]
if(fast == slow):
break
# f = 2s and f-s = nb; s = nb and f = 2nb
# 从头统计走过的步数k,当k = a + nb时,正好在入口节点
# 因此 让 slow 再向前走 a 步,正好到入口节点
finder = 0
while True:
finder = nums[finder]
slow = nums[slow]
if slow == finder:
break
return slow
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Codec:
def serialize(self, root):
"""Encodes a tree to a single string.
:type root: TreeNode
:rtype: str
"""
# # BFS
# if not root:
# return ""
# q = deque()
# q.append(root)
# res = ''
# while q:
# node = q.popleft()
# if node != None:
# res += str(node.val) + ','
# q.append(node.left)
# q.append(node.right)
# else:
# res += 'X,'
# return res
# DFS
if root == None: return 'X,'
leftserilized = self.serialize(root.left)
rightserilized = self.serialize(root.right)
return str(root.val) + ',' + leftserilized + rightserilized
def deserialize(self, data):
"""Decodes your encoded data to tree.
:type data: str
:rtype: TreeNode
"""
# # BFS
# if not data: return None
# data = data.split(',')
# root = TreeNode(data.pop(0))
# q = [root]
# while q:
# node = q.pop(0)
# if data:
# val = data.pop(0)
# if val != 'X':
# node.left = TreeNode(val)
# q.append(node.left)
# if data:
# val = data.pop(0)
# if val != 'X':
# node.right = TreeNode(val)
# q.append(node.right)
# return root
data = data.split(',')
root = self.buildTree(data)
return root
def buildTree(self,data):
val = data.pop(0)
if val == 'X': return None
node = TreeNode(val)
node.left = self.buildTree(data)
node.right = self.buildTree(data)
return node
# Your Codec object will be instantiated and called as such:
# ser = Codec()
# deser = Codec()
# ans = deser.deserialize(ser.serialize(root))
class Solution:
def __init__(self):
self.max_len = 0
self.max_valid = 0 # 最长可能的括号数
self.res_set = set()
self.n = 0
def removeInvalidParentheses(self, s: str) -> List[str]:
# DFS
# 全局变量记录最长长度 & 最终结果集合
@lru_cache(None)
def dfs(i, cur, score):
# print(i, cur, score)
# 剪枝
if score < 0 or score > self.max_valid:
return
# 截止条件: 到最后一个字符, score=0为合法字符串 & 长度大于当前最大 len,更新
if i == self.n:
if score == 0 and len(cur) >= self.max_len:
if len(cur) > self.max_len:
self.res_set.clear()
self.res_set.add(cur)
self.max_len = len(cur)
return
# 做选择
c = s[i]
if c == '(':
dfs(i+1, cur+c, score+1)
dfs(i+1, cur, score)
elif c == ')':
dfs(i+1, cur+c, score-1)
dfs(i+1, cur, score)
else:
dfs(i+1, cur+c, score)
self.n = len(s)
l, r = 0, 0
for ch in s:
if ch == '(':
l += 1
elif ch == ')':
r += 1
self.max_valid = min(l, r)
# print(s, self.max_valid)
dfs(0, "", 0)
return list(self.res_set)
class Solution:
def maxProfit(self, prices: List[int]) -> int:
# 动态规划
if not prices:
return 0
n = len(prices)
# f[i][0]: 手上持有股票的最大收益
# f[i][1]: 手上不持有股票,并且处于冷冻期中的累计最大收益
# f[i][2]: 手上不持有股票,并且不在冷冻期中的累计最大收益
f = [[-prices[0], 0, 0]] + [[0] * 3 for _ in range(n - 1)]
for i in range(1, n):
f[i][0] = max(f[i - 1][0], f[i - 1][2] - prices[i])
f[i][1] = f[i - 1][0] + prices[i]
f[i][2] = max(f[i - 1][1], f[i - 1][2])
return max(f[n - 1][1], f[n - 1][2])
312. 戳气球
class Solution:
def maxCoins(self, nums: List[int]) -> int:
# # 自顶向下,分治
# # 把戳气球操作倒过来,看做是每次增加一个气球
# n = len(nums)
# val = [1] + nums + [1]
# @lru_cache(None)
# def solve(i, j):
# if i >= j - 1:
# return 0
# res = 0
# for k in range(i+1, j):
# temp = val[i] * val[j] * val[k]
# temp += solve(i, k) + solve(k, j)
# res = max(res, temp)
# return res
# return solve(0, n+1)
# 动态规划
n = len(nums)
rec = [[0] * (n + 2) for _ in range(n + 2)]
val = [1] + nums + [1]
# 注意遍历顺序,i 需要倒序,j 正序
# 原因是 dp[i][j] 依赖 dp[i][k] 其中 k<j, dp[i][k]位于 dp[i][j]同行左侧,表示 j 需要正序遍历
# dp[i][j] 依赖 dp[k][j], 其中 k>i, dp[k][j] 位于 dp[i][j]同列下侧,表示 i 需要倒序遍历
for i in range(n - 1, -1, -1):
for j in range(i + 2, n + 2):
for k in range(i + 1, j):
total = val[i] * val[k] * val[j]
total += rec[i][k] + rec[k][j]
rec[i][j] = max(rec[i][j], total)
return rec[0][n + 1]