打家劫舍
获得不相邻的元素最大和
输入:[1,2,3,1]
输出:4
class Solution:
def rob(self, nums: List[int]) -> int:
lens = len(nums) # 获取输入列表的长度
if lens <= 2: # 如果长度小于等于2
return max(nums) # 返回列表中的最大值
before1 = nums[0] # 初始化 before1 为第一个元素的值
before2 = max(before1, nums[1]) # 初始化 before2 为前两个元素中的最大值
for i in range(2, lens): # 从第三个元素开始迭代
now = max(before2, before1 + nums[i]) # 计算当前最大值,要么不抢当前房子,要么抢当前房子
before1 = before2 # 更新 before1 为上一次的 before2
before2 = now # 更新 before2 为当前的最大值
return now # 返回计算出的最大值
完全平方数
class Solution:
def numSquares(self, n: int) -> int:
dp = [i for i in range(n+1)] # 初始化 dp 数组,dp[i] 表示 i 最少可以由多少个完全平方数之和组成
squares = [i*i for i in range(1, int(n**0.5)+1)] # 预先计算所有小于等于 n 的完全平方数
for i in range(4, n+1): # 从 4 开始遍历到 n
for j in squares: # 遍历所有的完全平方数
if j > i: # 如果完全平方数大于当前的 i
continue # 跳过后续的计算
dp[i] = min(dp[i], dp[i-j]+1) # 更新 dp[i] 为使用当前完全平方数 j 和之前的 dp[i-j] 的最小值
return dp[n] # 返回 dp[n],即 n 最少可以由多少个完全平方数之和组成
零钱兑换
计算并返回可以凑成总金额所需的 最少的硬币个数 。
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [float('inf') for i in range(amount+1)] # 初始化 dp 数组,dp[i] 表示组成金额 i 所需的最少硬币数
dp[0] = 0 # 组成金额 0 所需硬币数为 0
for i in coins[::-1]: # 逆序遍历硬币列表
for j in range(i, amount+1): # 从当前硬币金额 i 到目标金额 amount 遍历
dp[j] = min(dp[j], dp[j-i] + 1) # 更新 dp[j] 为使用当前硬币 i 时的最小值
# print(i, dp) # 如果需要,可以打印中间状态以调试
return dp[amount] if dp[amount] != float('inf') else -1 # 如果无法组成目标金额,返回 -1
单次拆分
给你一个字符串 s 和一个字符串列表 wordDict 作为字典。如果可以利用字典中出现的一个或多个单词拼接出 s 则返回 true。
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n = len(s) # 获取字符串 s 的长度
dp = [False for i in range(n+1)] # 初始化 dp 数组,dp[i] 表示 s 的前 i 个字符是否可以被拆分成字典中的单词
dp[0] = True # 空字符串可以被拆分
for i in range(n): # 遍历字符串的每个字符
for j in range(i+1, n+1): # 从 i+1 到 n 遍历
if dp[i] and s[i:j] in wordDict: # 如果 dp[i] 为 True 且子串 s[i:j] 在字典中
dp[j] = True # 更新 dp[j] 为 True,表示前 j 个字符可以被拆分
return dp[-1] # 返回 dp[n],即整个字符串 s 是否可以被拆分成字典中的单词
最长递增子序列
class Solution:
def lengthOfLIS(self, nums: List[int]) -> int:
dp = [1] * len(nums) # 初始化 dp 数组,每个元素初始化为 1,表示以当前元素为结尾的最长递增子序列长度至少为 1
for i in range(len(nums)): # 遍历数组的每一个元素
for j in range(0, i): # 遍历当前元素之前的所有元素
if nums[j] < nums[i]: # 如果前面的元素小于当前元素
dp[i] = max(dp[j] + 1, dp[i]) # 则更新 dp[i],为 dp[j] + 1 和 dp[i] 之间的最大值
return max(dp) # 返回 dp 数组中的最大值,即最长递增子序列的长度
乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
class Solution:
def maxProduct(self, nums: List[int]) -> int:
final_max = float('-inf') # 初始化最终最大值为负无穷大
fmin, fmax = 1, 1 # 初始化当前最小值和最大值为 1
for i in nums: # 遍历数组的每一个元素
if i < 0: # 如果当前元素小于 0
fmin, fmax = fmax, fmin # 交换当前最小值和最大值,因为乘以负数会逆转最大最小
fmax = max(fmax * i, i) # 更新当前最大值为当前元素或当前元素乘以之前的最大值
fmin = min(fmin * i, i) # 更新当前最小值为当前元素或当前元素乘以之前的最小值
final_max = max(fmax, final_max) # 更新最终最大值
return final_max # 返回最终最大值
分割等和子集
class Solution:
def canPartition(self, nums: List[int]) -> bool:
s = sum(nums) # 计算数组 nums 的总和
if s % 2: # 如果总和是奇数,无法平分
return False # 返回 False
s //= 2 # 将总和减半,目标是找出部分和为 s 的子集
n = len(nums) # 获取数组的长度
f = [[False] * (s + 1) for _ in range(n + 1)] # 初始化二维数组 f,大小为 (n+1) x (s+1)
f[0][0] = True # 初始状态,用空集合达到和为 0
for i, x in enumerate(nums): # 枚举数组中的每一个数
for j in range(s + 1): # 枚举每一个可能的和
f[i + 1][j] = j >= x and f[i][j - x] or f[i][j] # 更新状态,f[i][j] 表示用 nums[:i] 能达到和为 j
print(f[-1]) # 打印最后一行状态,用于调试
return f[n][s] # 返回是否能够找到一个子集,其和为 s
最长有效括号
class Solution:
def longestValidParentheses(self, s: str) -> int:
stack = [] # 栈用于存储索引
res = 0 # 存储最长有效括号长度
if not s: # 如果字符串为空
return 0 # 返回 0
for index, i in enumerate(s): # 遍历字符串中的每一个字符及其索引
if not stack or i == '(' or s[stack[-1]] == ')': # 如果栈为空,或者当前字符为 '(',或者栈顶对应的字符为 ')'
stack.append(index) # 将当前索引压入栈中
else: # 如果当前字符为 ')'
stack.pop() # 弹出栈顶元素
res = max(res, index - (stack[-1] if stack else -1)) # 更新最长有效括号长度
return res # 返回最长有效括号长度