动态规划
题目list【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台】
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for x in range(coin, amount+1):
dp[x] = min(dp[x], dp[x - coin] + 1)
if dp[amount] != float('inf'):
return dp[amount]
else:
return -1
-
LC322【零钱兑换】
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
dp = [float('inf')] * (amount + 1)
dp[0] = 0
for coin in coins:
for x in range(coin, amount+1):
dp[x] = min(dp[x], dp[x - coin] + 1)
if dp[amount] != float('inf'):
return dp[amount]
else:
return -1
-
LC139【单词拆分】
class Solution:
def wordBreak(self, s: str, wordDict: List[str]) -> bool:
n = len(s)
dp = [False] * (n + 1)
dp[0] = True
dic = set(wordDict)
for i in range(1, n+1):
for j in range(i):
if dp[j] and s[j:i] in dic:
dp[i] = True
break
return dp[n]
def solve(nums):
if not nums:
return -1
l = len(nums)
dp = [1] * l
max_len = 1 # 长度至少也是1
for i in range(1, l):
for j in range(i):
if nums[j] < nums[i]:
dp[i] = max(dp[j]+1, dp[i])
if dp[i] > max_len:
max_len = dp[i]
return max_len
-
合唱团【合唱团(牛客) - 代码先锋网】
def solve(nums):
num1 = kernel(nums)
print(num1)
num2 = kernel(nums[::-1])
print(num2)
res = []
ans = -1
for i in range(len(num1)):
cur = num1[i] + num2[i] - 1
res.append(cur)
ans = max(ans, res[i])
return len(nums) - ans
def kernel(nums):
n = len(nums)
dp = [1] * n
res = 1
for i in range(1, n):
for j in range(i):
if nums[i] > nums[j]:
dp[i] = max(dp[j]+1, dp[i])
res = max(res, dp[i])
return dp
-
LC674:最长连续递增序列【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台】
def solve(nums):
if not nums:
return -1
ans = 1
l = len(nums)
start = 0
for i in range(l):
if i > 0 and nums[i] <= nums[i-1]:
start = i
ans = max(ans, i - start + 1)
return ans
-
LC718:最长重复子数组
def solve(nums1, nums2):
m ,n = len(nums1), len(nums2)
dp = [[0] * (n + 1) for i in range(m+1)]
ans = 0
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
if nums1[i] == nums2[j]:
dp[i][j] = dp[i+1][j+1] + 1
else:
dp[i][j] = 0
ans = max(ans, dp[i][j])
return ans
-
LC1143:最长公共子序列
def solve(text1, text2):
m, n = len(text1), len(text2)
dp = [[0] * (n + 1) for i in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if text1[i-1] == text2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
-
LC1035:不相交的线【本质为最长公共子序列】
def solve(nums1, nums2):
m, n = len(nums1), len(nums2)
dp = [[0] * (n + 1) for i in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if nums1[i-1] == nums2[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
-
LC53:最大子序和【连续】
def solve(nums):
pre = 0
max_sum = nums[0]
for each in nums:
pre = max(pre + each, each) # 当前数字大,还是加上当前数字之前的一段大
max_sum = max(pre, max_sum)
return max_sum
def solve(nums):
if not nums:
return -1
n = len(nums)
dp = [0] * n
dp[0] = nums[0]
res = nums[0]
for i in range(1, n):
if dp[i-1] >= 0:
dp[i] = dp[i-1] + nums[i]
else:
dp[i] = nums[i]
res = max(res, dp[i])
return res
-
LC918【环形子数组最大和】
class Solution:
def maxSubarraySumCircular(self, nums: List[int]) -> int:
total = 0
maxsum = nums[0]
minsum = nums[0]
cur_max = 0
cur_min = 0
for each in nums:
cur_max = max(cur_max + each, each)
maxsum = max(maxsum, cur_max)
cur_min = min(cur_min + each, each)
minsum = min(minsum, cur_min)
total += each
if maxsum < 0:
return maxsum
else:
return max(maxsum, total - minsum)
-
LC152【乘积最大子数组】
class Solution:
def maxProduct(self, nums: List[int]) -> int:
res = nums[0]
pre_max = nums[0]
pre_min = nums[0]
for each in nums[1:]:
cur_max = max(pre_max * each, pre_min * each, each)
cur_min = min(pre_max * each, pre_min * each, each)
res = max(res, cur_max)
pre_max = cur_max
pre_min = cur_min
return res
-
LC392:判断子序列
def solve(s, t):
m, n = len(s), len(t)
i = 0
j = 0
while i < m and j < n:
if s[i] == t[j]:
i += 1
j += 1
return i == m
# 动态规划(最长公共子序列,判断最长子序列长度是否等于m)
def solve(s, t):
m, n = len(s), len(t)
dp = [[0] * (n+1) for i in range(m+1)]
max_len = 0
for i in range(1, m+1):
for j in range(1, n+1):
if s[i-1] == t[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
max_len = max(max_len, dp[i][j])
return max_len == m
-
LC673:最长递增子序列个数
def solve(nums):
n = len(nums)
max_len = 0 # 最长长度
ans = 0
dp = [1] * n
cnt = [1] * n
for i in range(n):
for j in range(i):
if nums[i] > nums[j]:
if dp[j] + 1 > dp[i]:
dp[i] = dp[j] + 1
cnt[i] = cnt[j]
elif dp[j] + 1 == dp[i]:
cnt[i] += cnt[j]
if dp[i] > max_len:
max_len = dp[i]
ans = cnt[i]
elif dp[i] == max_len:
ans += cnt[i]
return ans
-
LC72:编辑距离
def solve(word1, word2):
m, n = len(word1), len(word2)
dp = [[0] * (n + 1) for i in range(m + 1)]
for i in range(1, m+1):
dp[i][0] = dp[i-1][0] + 1
for j in range(1, n + 1):
dp[0][j] = dp[0][j-1] + 1
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] = min(dp[i-1][j-1] + 1, dp[i][j-1] + 1, dp[i-1][j] + 1)
return dp[m][n]
-
# jianshengzi def solve(nums): n = nums dp = [0] * (n + 1) dp[1], dp[2] = 1, 1 for i in range(3, n+1): for j in range(i): dp[i] = max(dp[i], max(dp[i-j] * j, j * (i - j))) return dp[n]
-
LC582:两个字符串的删除操作
# 方法1:dp
def solve(word1, word2):
m, n = len(word1), len(word2)
dp = [[0] * (n+1) for i in range(m+1)]
for i in range(1, m+1):
dp[i][0] = dp[i-1][0] + 1
for j in range(1, n+1):
dp[0][j] = dp[0][j-1] + 1
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] = min(dp[i-1][j]+1, dp[i][j-1]+1)
return dp[m][n]
# 方法2:最长公共子序列
def solve(word1, word2):
m, n = len(word1), len(word2)
dp = [[0] * (n+1) for i in range(m+1)]
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] + 1
else:
dp[i][j] = max(dp[i][j-1], dp[i-1][j])
max_len = dp[m][n]
res = m - max_len + n - max_len
return res
-
LC115:不同子序列的个数
# 不同子序列的个数(t是s的子序列)
def solve(s, t):
m, n = len(s), len(t)
if m < n:
return 0
dp = [[0] * (n+1) for i in range(m+1)] # dp[i][j]表示s[i:]在t[j:]中不同子序列的个数
for i in range(m+1):
dp[i][n] = 1
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
if s[i] == t[j]:
dp[i][j] = dp[i+1][j+1] + dp[i+1][j]
else:
dp[i][j] = dp[i+1][j]
return dp[0][0]
-
LC516:最长回文子序列
def solve(s):
n = len(s)
dp = [[0] * n for i in range(n)] # dp[i][j]表示s中i和j之间的字符串的最长回文子序列长度
for i in range(n-1, -1, -1):
dp[i][i] = 1
for j in range(i+1, n):
if s[i] == s[j]:
dp[i][j] = dp[i+1][j-1] + 2
else:
dp[i][j] = max(dp[i+1][j], dp[i][j-1])
return dp[0][n-1]
-
LC5:最长回文子串
def solve(s):
nums = s
n = len(nums)
if n < 2:
return nums
dp = [[0] * n for i in range(n)]
max_len = 1
begin = 0
for i in range(n):
dp[i][i] = 1
for L in range(2, n+1):
for i in range(n):
j = i + L - 1
if j >= n:
break
if nums[i] != nums[j]:
dp[i][j] = 0
else:
if j - i < 3:
dp[i][j] = 1
else:
dp[i][j] = dp[i+1][j-1]
if dp[i][j] and L > max_len:
max_len = L
begin = i
return nums[begin:begin+max_len]
-
LC70:爬楼梯
def solve(n):
if n < 3:
return n
f0 = 1
f1 = 2
for i in range(3, n+1):
fn = f0 + f1
f0 = f1
f1 = fn
return fn
-
LC746:使用最小花费爬楼梯
def solve(cost):
n = len(cost)
dp = [0] * (n+1)
for i in range(2, n+1):
dp[i] = min(dp[i-1] + cost[i-1], dp[i-2] + cost[i-2])
return dp[n]
-
LC121:买卖股票最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
def solve(prices):
minPrice = 1e20
maxProfit = -1
for i in range(len(prices)):
if prices[i] < minPrice:
minPrice = prices[i]
maxProfit = max(maxProfit, prices[i]-minPrice)
return maxProfit
-
LC122:买卖股票最佳时机2
给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。
返回 你能获得的 最大 利润 。
def solve(prices):
n = len(prices)
dp = [[0] * 2 for i in range(n)]
dp[0][0] = 0
dp[0][1] = -prices[0]
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][0] - prices[i], dp[i-1][1])
return dp[n-1][0]
-
LC309:买卖股票最佳时机【含冷冻期】
'''
dp[i][0]:持有股票
dp[i][1]:不持有股票(不在冷冻期)
dp[i][2]:不持有股票(在冷冻期)
'''
def solve(prices):
n = len(prices)
dp = [[0] * 3 for i in range(n)]
dp[0][0] = -prices[0]
dp[0][1] = 0
dp[0][2] = 0
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][2])
dp[i][2] = dp[i-1][0] + prices[i]
return max(dp[n-1][1], dp[n-1][2])
-
LC714:买卖股票最佳时机【含手续费】
'''
dp[i][0]:有股票
dp[i][1]:没有股票
'''
def solve(prices, fee):
n = len(prices)
dp = [[0] * 2 for i in range(n)]
dp[0][0] = -prices[0]
dp[0][1] = 0
for i in range(1, n):
dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i])
dp[i][1] = max(dp[i-1][0] + prices[i] - fee, dp[i-1][1])
return dp[n-1][1]
-
LC198:打家劫舍
def solve(nums):
if not nums:
return 0
n = len(nums)
if n == 1:
return nums[0]
dp = [0] * n
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[-1]
-
LC337:树形打家劫舍
# 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 rob(self, root: Optional[TreeNode]) -> int:
def dfs(root):
if not root:
return 0, 0
l_rob, l_not_rob = dfs(root.left)
r_rob, r_not_rob = dfs(root.right)
rob = l_not_rob + r_not_rob + root.val
not_rob = max(l_rob, l_not_rob) + max(r_rob, r_not_rob)
return rob, not_rob
return max(dfs(root))
-
LC739【每日温度】
class Solution:
def dailyTemperatures(self, nums: List[int]) -> List[int]:
n = len(nums)
res = [0] * n
stack = []
for i in range(n - 1, -1, -1):
while stack and nums[i] >= nums[stack[-1]]:
stack.pop()
if stack:
res[i] = stack[-1] - i
stack.append(i)
return res
-
LC983:最低票价
def solve(days, costs):
maxDays = days[-1]
dp = [0] * (maxDays + 31) #防止越界
for d in range(maxDays, -1, -1):
if d in days:
dp[d] = min(dp[d+1] + costs[0], dp[d+7]+costs[1], dp[d+30]+costs[2])
else:
dp[d] = dp[d+1]
return dp[0]
多维动态规划
1. LC120【三角形最小路径和】
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
f = [[0] * n for i in range(n)]
f[0][0] = triangle[0][0]
# res = float('inf')
for i in range(1, n):
f[i][0] = f[i-1][0] + triangle[i][0]
for j in range(1, i):
f[i][j] = min(f[i-1][j-1], f[i-1][j]) + triangle[i][j]
f[i][i] = f[i-1][i-1] + triangle[i][i]
# res = min(res, f[i])
return min(f[n-1])
2. LC64【最小路径和】
class Solution:
def minPathSum(self, grid: List[List[int]]) -> int:
m ,n = len(grid), 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] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
return dp[m-1][n-1]
3. LC62【不同路径】
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
dp = [[0] * n for i in range(m)]
dp[0][0] = 1
for i in range(1, m):
dp[i][0] = dp[i-1][0]
for j in range(1, n):
dp[0][j] = dp[0][j-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]
4、LC63【不同路径有障碍物】
class Solution:
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
m, n = len(obstacleGrid), len(obstacleGrid[0])
dp = [[0] * n for i in range(m)]
if obstacleGrid[0][0] == 1:
dp[0][0] = 0
else:
dp[0][0] = 1
for i in range(1, m):
if obstacleGrid[i][0] == 1:
dp[i][0] = 0
else:
dp[i][0] = dp[i-1][0]
for j in range(1, n):
if obstacleGrid[0][j] == 1:
dp[0][j] = 0
else:
dp[0][j] = dp[0][j-1]
for i in range(1, m):
for j in range(1, n):
if obstacleGrid[i][j] == 1:
dp[i][j] = 0
else:
dp[i][j] = dp[i-1][j] + dp[i][j-1]
return dp[m-1][n-1]
5. LC221【最大正方形】
class Solution:
def maximalSquare(self, matrix: List[List[str]]) -> int:
res = 0
m, n = len(matrix), len(matrix[0])
dp = [[0] * n for i in range(m)]
for i in range(m):
for j in range(n):
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-1][j-1], dp[i][j-1]) + 1
res = max(res, dp[i][j])
return res * res
位运算、数组
-
LC41【缺失的第一个正数】
class Solution:
def firstMissingPositive(self, nums: List[int]) -> int:
n = len(nums)
for i in range(n):
while 1 <= nums[i] <= n and nums[nums[i] - 1] != nums[i]:
nums[nums[i] - 1], nums[i] = nums[i], nums[nums[i] - 1]
for i in range(n):
if nums[i] != i + 1:
return i + 1
return n + 1
-
LC151【反转字符串中的单词】
class Solution:
def reverseWords(self, s: str) -> str:
s = s.strip()
left = right = len(s) - 1
res = []
while left >= 0:
while left >= 0 and s[left] != ' ':
left -= 1
res.append(s[left + 1:right + 1])
while left >= 0 and s[left] == ' ':
left -= 1
right = left
return ' '.join(res)
-
LC14【最长公共前缀】
class Solution:
def longestCommonPrefix(self, strs: List[str]) -> str:
prefix = strs[0]
n = len(strs)
for i in range(1, n):
prefix = self.kernel(prefix, strs[i])
if not prefix:
break
return prefix
def kernel(self, s1, s2):
n = min(len(s1), len(s2))
count = 0
while count < n and s1[count] == s2[count]:
count += 1
return s1[:count]
-
LC42【接雨水】
class Solution:
def trap(self, height: List[int]) -> int:
n = len(height)
left = [0] * n
left[0] = height[0]
for i in range(1, n):
left[i] = max(left[i-1], height[i])
right = [0] * n
right[n-1] = height[-1]
for j in range(n-2,-1,-1):
right[j] = max(right[j+1], height[j])
res = 0
for i in range(n):
cur = min(left[i], right[i]) - height[i]
res += cur
return res
-
LC135【分发糖果】
class Solution:
def candy(self, ratings: List[int]) -> int:
n = len(ratings)
left = [0] * n
for i in range(n):
if i > 0 and ratings[i] > ratings[i-1]:
left[i] = left[i-1] + 1
else:
left[i] = 1
right = 0
res = 0
for i in range(n-1, -1, -1):
if i < n - 1 and ratings[i] > ratings[i+1]:
right = right + 1
else:
right = 1
res = res + max(left[i], right)
return res
-
LC238【除自身以外数组的乘积】
class Solution:
def productExceptSelf(self, nums: List[int]) -> List[int]:
n = len(nums)
res1 = [1] * n
for i in range(1, n):
res1[i] = res1[i-1] * nums[i-1]
res2 = [1] * n
for i in range(n-2, -1, -1):
res2[i] = res2[i+1] * nums[i+1]
res = []
for i in range(n):
res.append(res1[i] * res2[i])
return res
-
LC55【跳跃游戏】
class Solution:
def canJump(self, nums: List[int]) -> bool:
n = len(nums)
most = 0
for i in range(n):
if i <= most:
most = max(most, i + nums[i])
if most >= n - 1:
return True
return False
-
LC45【跳跃游戏2】
class Solution:
def jump(self, nums: List[int]) -> int:
n = len(nums)
most = 0
res = 0
end = 0
for i in range(n-1):
if i <= most:
most = max(most, i + nums[i])
if i == end:
end = most
res += 1
return res
-
LC136:只出现一次的数字(只有一个数字出现一次,其他均出现两次)
def solve(nums):
res = nums[0]
n = len(nums)
for i in range(1, n):
res = res ^ nums[i]
return res
-
LC268:丢失的数字(给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。)
def solve(nums):
ans = 0
for i in range(len(nums)):
ans = ans ^ nums[i]
for i in range(len(nums)+1):
ans = ans ^ i
# print(i, nums[i])
# print(ans)
return ans
-
LC141:环形链表
# 哈希
def solve(head):
seen = set()
while head:
if head in seen:
return True
else:
seen.add(head)
head = head.next
return False
# 快慢指针
def solve(head):
if not head or not head.next:
return False
slow = head
fast = head.next
while slow != fast:
if not fast or not fast.next:
return False
slow = slow.next
fast = fast.next.next
return True
-
LC142:环形链表2【若有环,寻找环的入口】
def solve(head):
fast, slow = head, head
while True:
if not fast or not fast.next:
return None
fast = fast.next.next
slow = slow.next
if fast == slow:
break
fast = head
while fast != slow:
fast = fast.next
slow = slow.next
return fast
数组、二分、双指针
-
LC713【乘积小于k的子数组个数】
class Solution:
def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
if k <= 1:
return 0
target = k
left, right = 0, 0
n = len(nums)
res = 0
total = 1
for i in range(n):
total *= nums[right]
while total >= target:
total /= nums[left]
left += 1
res += right - left + 1
right += 1
return res
-
LC209【长度最小的子数组】
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
left, right = 0, 0
n = len(nums)
res = n + 1
total = 0
while right < n:
total += nums[right]
while total >= target:
res = min(res, right - left + 1)
total -= nums[left]
left += 1
right += 1
if res == n + 1:
return 0
else:
return res
-
LC15【三数之和】
class Solution:
def threeSum(self, nums: List[int]) -> List[List[int]]:
nums.sort()
n = len(nums)
res = []
for k in range(n - 2):
if nums[k] > 0:
break
if k > 0 and nums[k] == nums[k-1]:
continue
i, j = k + 1, n - 1
while i < j:
s = nums[i] + nums[j] + nums[k]
if s > 0:
j -= 1
while i < j and nums[j] == nums[j+1]:
j -= 1
elif s < 0:
i += 1
while i < j and nums[i] == nums[i-1]:
i += 1
else:
res.append([nums[i], nums[j], nums[k]])
i += 1
j -= 1
while i < j and nums[i] == nums[i-1]:
i += 1
while i < j and nums[j] == nums[j+1]:
j -= 1
return res
-
LC11【盛水最多的容器】
class Solution:
def maxArea(self, height: List[int]) -> int:
left, right = 0, len(height)-1
res = 0
while left < right:
if height[left] < height[right]:
res = max(res, height[left] * (right - left))
left += 1
else:
res = max(res, height[right] * (right - left))
right -= 1
return res
-
LC392【判断子序列】
class Solution:
def isSubsequence(self, s: str, t: str) -> bool:
m, n = len(s), len(t)
i, j = 0, 0
while i < m and j < n:
if s[i] == t[j]:
i += 1
j += 1
else:
j += 1
return i == m
-
LC26:原地删除有序数组重复值
def solve(nums):
n = len(nums)
slow, fast = 1, 1
while fast < n:
if nums[fast] != nums[fast-1]:
nums[slow] = nums[fast]
slow += 1
fast += 1
return slow
-
LC3:无重复字符的最长子串
-
def solve(s): dic = set() right = -1 res = 0 n = len(s) for i in range(n): if i != 0: dic.remove(s[i-1]) while (right + 1) < n and s[right+1] not in dic: dic.add(s[right+1]) right += 1 res = max(res, right - i + 1) return res
-
排序数组目标值的起始位置和结束位置
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
start = self.kernel(nums, target)
# print(start)
if start == len(nums) or nums[start] != target:
# if start == len(nums):
return [-1, -1]
right = self.kernel(nums, target + 1) - 1
return [start, right]
def kernel(self, nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
# if nums[mid ] < target:
# left = mid + 1
# else:
# right = mid - 1
if nums[mid ] >= target:
right = mid - 1
else:
left = mid + 1
return left
-
剑指11:旋转数组最小值
def solve(numbers):
low, high = 0, len(numbers) - 1
while low <= high:
if numbers[low] < numbers[high]:
return numbers[low] # 如果是有序数组 直接返回numbers[low]
mid = (low + high) // 2
if numbers[mid] > numbers[low]:
low = mid + 1
elif numbers[mid] < numbers[low]:
high = mid
else:
low += 1
return numbers[mid]
-
LC33:搜索排序旋转数组【无重复值】
# 先寻找有序的一部分
def solve(nums, target):
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[mid] == target:
return mid
if nums[mid] >= nums[low]: # 注意等号
if target < nums[mid] and target >= nums[low]:
high = mid - 1
else:
low = mid + 1
else:
if target > nums[mid] and target <= nums[len(nums)-1]:
low = mid + 1
else:
high = mid - 1
return -1
-
LC81:搜索排序旋转数组【有重复值】
# 先寻找有序的一部分
def solve(nums, target):
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) // 2
if nums[mid] == target:
return True
if nums[low] == nums[mid] and nums[mid] == nums[high]:
low += 1
high -= 1
elif nums[mid] >= nums[low]: # 注意等号
if target < nums[mid] and target >= nums[low]:
high = mid - 1
else:
low = mid + 1
else:
if target > nums[mid] and target <= nums[len(nums)-1]:
low = mid + 1
else:
high = mid - 1
return False
-
LC240:搜索二维矩阵2(行升序、列升序)
# z型搜索
def solve(matrix, target):
row, col = len(matrix), len(matrix[0])
x, y = 0, col-1
while x < row and y >= 0:
if matrix[x][y] == target:
return True
elif matrix[x][y] > target:
y -= 1
else:
x += 1
return False
-
LC88:合并两个有序数组(非递减顺序)
# 双指针
def solve(nums1, m, nums2, n):
res = []
p1, p2 = 0, 0
while p1 < m or p2 < n:
if p1 == m:
res.append(nums2[p2])
p2 += 1
elif p2 == n:
res.append(nums1[p1])
p1 += 1
elif nums1[p1] < nums2[p2]:
res.append(nums1[p1])
p1 += 1
else:
res.append(nums2[p2])
p2 += 1
nums1[:] = res
滑动窗口
1、LC3【无重复字符的最长字串】
class Solution:
def lengthOfLongestSubstring(self, s: str) -> int:
dic = set()
right = -1
n = len(s)
res = 0
for i in range(n):
if i != 0:
dic.remove(s[i-1])
while right + 1 < n and s[right + 1] not in dic:
dic.add(s[right + 1])
right += 1
res = max(res, right - i + 1)
return res
链表
-
LC86【分隔链表】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:
small_dummy, big_dummy = ListNode(), ListNode()
small, big = small_dummy, big_dummy
while head:
if head.val < x:
small.next = head
small = small.next
else:
big.next = head
big = big.next
head = head.next
small.next = big_dummy.next
big.next = None
return small_dummy.next
-
LC82【删除排序链表的重复元素】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
dummy = ListNode(0, head)
cur = dummy
while cur.next and cur.next.next:
if cur.next.val == cur.next.next.val:
x = cur.next.val
while cur.next and cur.next.val == x:
cur.next = cur.next.next
else:
cur = cur.next
return dummy.next
-
LC19【删除链表的倒数第N个节点】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def removeNthFromEnd(self, head: Optional[ListNode], n: int) -> Optional[ListNode]:
dummy = ListNode(next = head)
cur = dummy
cur1 = head
k = 0
while cur1:
k += 1
cur1 = cur1.next
# cur = dummy/
for i in range(1, k - n + 1):
cur = cur.next
cur.next = cur.next.next
return dummy.next
-
LC2【两数相加】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
cur = dummy = ListNode(0)
carry = 0
while l1 or l2 or carry:
carry += (l1.val if l1 else 0) + (l2.val if l2 else 0)
cur.next = ListNode(carry % 10)
carry //= 10
cur = cur.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
return dummy.next
-
LC25【k个一组反转链表】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseKGroup(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
n = 0
cur = head
while cur:
n += 1
cur = cur.next
p0 = dummy = ListNode(next = head)
cur, pre = head, None
while n >= k:
n -= k
for i in range(k):
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
tmp = p0.next
tmp.next = cur
p0.next = pre
p0 = tmp
return dummy.next
-
LC206【反转链表】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseList(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur, pre = head, None
while cur:
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
return pre
-
LC92【反转链表2】
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
p0 = dummy = ListNode(next = head)
for _ in range(left - 1):
p0 = p0.next
pre = None
cur = p0.next
for _ in range(right - left + 1):
tmp = cur.next
cur.next = pre
pre = cur
cur = tmp
'''
比如(例子1)原来1后连着2(1->next=2),现在2到后面去了,我想要2连着5,那就是2->next=5,合起来就是1->next->next=5。第二句是1后连着4,也就是当前的pre位置
'''
p0.next.next = cur
p0.next = pre
return dummy.next
-
LC21:合并两个有序链表
# 递归
def solve(list1, list2):
if list1 is None:
return list2
elif list2 is None:
return list1
elif list1.val < list2.val:
list1.next = solve(list1.next, list2)
return list1
else:
list2.next = solve(list1, list2.next)
return list2
# 迭代
def solve(list1, list2):
prehead = ListNode(-1)
prev = prehead
while list1 and list2:
if list1.val < list2.val:
prev.next = list1
list1 = list1.next
else:
prev.next = list2
list2 = list2.next
prev = prev.next
if not list1:
prev.next = list2
else:
prev.next = list1
return prehead.next
-
LC148:排序链表
# 归并法 递归
def solve(head):
def sortKernel(head, tail):
if not head:
return head
if head.next == tail:
head.next = None
return head
slow = fast = head # 寻找中点
while fast != tail:
slow = slow.next
fast = fast.next
if fast != tail:
fast = fast.next
mid = slow
return merge(sortKernel(head, mid), sortKernel(mid, tail))
def merge(list1, list2):
prehead = ListNode(-1)
prev = prehead
while list1 and list2:
if list1.val <= list2.val:
prev.next = list1
list1 = list1.next
else:
prev.next = list2
list2 = list2.next
prev = prev.next
if not list1:
prev.next = list2
if not list2:
prev.next = list1
return prehead.next
return sortKernel(head, None)
-
LC23:合并k个有序链表
# 暴力 顺序合并 时间复杂度O(K^2*n)
def solve(lists):
ans = None
for i in range(len(lists)):
ans = kernel(ans, lists[i])
return ans
def kernel(list1, list2):
if list1 is None:
return list2
if list2 is None:
return list1
prehead = ListNode(-1)
prev = prehead
while list1 and list2:
if list1.val < list2.val:
prev.next = list1
list1 = list1.next
else:
prev.next = list2
list2 = list2.next
prev = prev.next
if not list1:
prev.next = list2
else:
prev.next = list1
return prehead.next
# 分治合并
def solve(lists):
return merge(lists, 0, len(lists)-1)
def merge(lists, left, right):
if left == right:
return lists[left]
if left > right:
return None
mid = (left + right) // 2
return kernel(merge(lists, left, mid), merge(lists, mid+1, right))
def kernel(list1, list2):
if list1 is None:
return list2
if list2 is None:
return list1
prehead = ListNode(-1)
prev = prehead
while list1 and list2:
if list1.val < list2.val:
prev.next = list1
list1 = list1.next
else:
prev.next = list2
list2 = list2.next
prev = prev.next
if not list1:
prev.next = list2
else:
prev.next = list1
return prehead.next
-
LC19【删除倒数第k个链表】
-
# shanchudaoshudikgejiedian def solve(head, n): dummy = ListNode(0, head) first = head second = dummy for i in range(n): first = first.next while first: first = first.next second = second.next second.next = second.next.next return dummy.next
-
LC160:相交链表
#空间复杂度o(m),m为headA长度
def solve(headA, headB):
seen = set()
while headA:
seen.add(headA)
headA = headA.next
while headB:
if headB in seen:
return headB
headB = headB.next
return None
# 空间复杂度o(1)
def solve(headA, headB):
if headA is None or headB is None:
return None
pa, pb = headA, headB
while pa != pb:
if pa is not None:
pa = pa.next
else:
pa = headB
if pb is not None:
pb = pb.next
else:
pb = headA
return pa
深度优先、广度优先、并查集
-
LC200:岛屿数量
给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量。
岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。
此外,你可以假设该网格的四条边均被水包围。
# 深度优先
def solve(grid):
row = len(grid)
col = len(grid[0])
res = 0
for x in range(row):
for y in range(col):
if grid[x][y] == '1':
res += 1
dfs(grid, x, y)
return res
def dfs(grid, x, y):
grid[x][y] = 0
row = len(grid)
col = len(grid[0])
for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
# print(i, j)
if i >= 0 and i < row and j >= 0 and j < col and grid[i][j] == '1': # 注意grid[i][j] == '1'的判断要放到最后, 否则数组越界
dfs(grid, i, j)
# 广度优先
import collections
def solve(grid):
row = len(grid)
col = len(grid[0])
res = 0
for x in range(row):
for y in range(col):
if grid[x][y] == '1':
res += 1
grid[x][y] = '0'
neighbours = collections.deque([(x, y)])
while neighbours:
r, c = neighbours.popleft()
for i, j in ([r-1, c], [r+1, c], [r, c-1], [r, c+1]):
if i >= 0 and i < row and j >= 0 and j < col and grid[i][j] == '1':
grid[i][j] = '0'
neighbours.append([i, j])
return res
-
LC130:被围绕的区域
# 深度优先
def solve(board):
row = len(board)
col = len(board[0])
def dfs(x, y):
if not (x >= 0 and x < row) or not(y >= 0 and y < col) 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 in range(row):
dfs(i, 0)
dfs(i, col-1)
for i in range(col-1):
dfs(0, i)
dfs(row-1, i)
for i in range(row):
for j in range(col):
if board[i][j] == 'A':
board[i][j] = 'O'
elif board[i][j] == 'O':
board[i][j] = 'X'
# 广度优先
def solve(board):
row, col = len(board), len(board[0])
quene = collections.deque()
for i in range(row):
if board[i][0] == 'O':
board[i][0] = 'A'
quene.append((i, 0))
if board[i][col-1] == 'O':
board[i][col-1] = 'A'
quene.append((i, col-1))
for i in range(col):
if board[0][i] == 'O':
board[0][i] = 'A'
quene.append((0, i))
if board[row-1][i] == 'O':
board[row-1][i] = 'A'
quene.append((row-1, i))
while quene:
x, y = quene.popleft()
for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
if i >= 0 and i < row and j >= 0 and j < col and board[i][j] == 'O':
board[i][j] = 'A'
quene.append((i, j))
for i in range(row):
for j in range(col):
if board[i][j] == 'A':
board[i][j] = 'O'
elif board[i][j] == 'O':
board[i][j] = 'X'
-
LC695:岛屿最大面积
# 深度优先
def solve(grid):
row = len(grid)
col = len(grid[0])
ans = 0
for i in range(row):
for j in range(col):
ans = max(dfs(grid, i, j), ans)
return ans
def dfs(grid, x, y):
row, col = len(grid), len(grid[0])
if x < 0 or y < 0 or x == row or y == col or grid[x][y] != 1:
return 0
grid[x][y] = 0
ans = 1
for i, j in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
ans += dfs(grid, i, j)
return ans
# 广度优先
# 广度优先
def solve(grid):
row, col = len(grid), len(grid[0])
ans = 0
for i in range(row):
for j in range(col):
cur = 0
quene = collections.deque([(i, j)])
while quene:
x, y = quene.popleft()
if x < 0 or x == row or y < 0 or y == col or grid[x][y] != 1:
continue
grid[x][y] = 0
cur += 1
for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
quene.append([tmp_x, tmp_y])
ans = max(ans, cur)
return ans
-
LC463:岛屿的周长(只有一个岛屿)
# 深度优先
def solve(grid):
row, col = len(grid), len(grid[0])
ans = 0
for i in range(row):
for j in range(col):
if grid[i][j] == 1:
ans += dfs(i, j, grid)
return ans
def dfs(i, j, grid):
row, col = len(grid), len(grid[0])
if i < 0 or i == row or j < 0 or j == col or grid[i][j] == 0:
return 1
if grid[i][j] == 2:
return 0
grid[i][j] = 2
ans = 0
for x, y in [(i-1, j),(i+1, j), (i, j-1), (i, j+1)]:
ans += dfs(x, y, grid)
return ans
# 广度优先
def solve(grid):
row, col = len(grid), len(grid[0])
ans = 0
for i in range(row):
for j in range(col):
if grid[i][j] == 1:
cur = 0
quene = collections.deque([(i, j)])
while quene:
x, y = quene.popleft()
grid[x][y] = 2
for tmp_x, tmp_y in [(x-1, y), (x+1, y), (x, y-1), (x, y+1)]:
if tmp_x < 0 or tmp_x == row or tmp_y < 0 or tmp_y == col or grid[tmp_x][tmp_y] == 0:
cur += 1
elif grid[tmp_x][tmp_y] == 1:
grid[tmp_x][tmp_y] = 2
quene.append([tmp_x, tmp_y])
ans += cur
return ans
-
LC102:二叉树的层序遍历
# bfs
def solve(root):
if not root:
return []
res = []
quene = [root]
while quene:
size = len(quene)
tmp = []
for i in range(size):
r = quene.pop(0)
tmp.append(r.val)
if r.left:
quene.append(r.left)
if r.right:
quene.append(r.right)
res.append(tmp)
return res
# dfs
def solve(root):
if not root:
return []
res = []
def dfs(index, r):
if len(res) < index:
res.append([])
res[index-1].append(r.val)
if r.left:
dfs(index+1, r.left)
if r.right:
dfs(index+1, r.right)
dfs(1, root)
return res
-
LC103:二叉树锯齿形遍历
# bfs
def solve(root):
if not root:
return []
res = []
quene = [root]
flag = 1
while quene:
size = len(quene)
tmp = []
for i in range(size):
r = quene.pop(0)
tmp.append(r.val)
if r.left:
quene.append(r.left)
if r.right:
quene.append(r.right)
if flag:
res.append(tmp)
flag = 0
else:
res.append(tmp[::-1])
flag = 1
return res
-
LC297:二叉树序列化反序列化
# bfs
class Solve:
def serialize(self, root):
if not root:
return ''
quene = [root]
res = []
while quene:
node = quene.pop(0)
if node:
res.append(str(node.val))
quene.append(node.left)
quene.append(node.right)
else:
res.append('null')
return '[' + ','.join(res) + ']'
def deserialize(self, data):
if not data:
return []
lst = data[1:-1].strip().split(',')
root = TreeNode(int(lst[0]))
quene = [root]
i = 1
while quene:
node = quene.pop(0)
if lst[i] != 'null':
node.left = TreeNode(int(lst[i]))
quene.append(node.left)
i += 1
if lst[i] != 'null':
node.right = TreeNode(int(lst[i]))
quene.append(node.right)
i += 1
return root
# dfs
class Solve:
def serialize(self, root):
if not root:
return 'null'
return str(root.val) + ',' + str(self.serialize(root.left)) + ',' + str(self.serialize(root.right))
def deserialize(self, data):
def dfs(lst):
val = lst.pop(0)
if val == 'null':
return None
root = TreeNode(int(val))
root.left = dfs(lst)
root.right = dfs(lst)
return root
lst = data.strip().split(',')
return dfs(lst)
排序
-
山峰数组最大值索引
class Solution:
def findPeakElement(self, nums: List[int]) -> int:
n = len(nums)
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) // 2
if nums[mid] > nums[mid + 1]:
right = mid
else:
left = mid + 1
return right
# shanfengshuzu
def solve(nums):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] > nums[mid + 1]:
right = mid - 1
else:
left = mid + 1
return left
-
LC215:数组中第k大元素
# 快排 (时间复杂度期望为o(n))
def solve(nums, k):
k = len(nums) - k
start = 0
end = len(nums) - 1
while True:
loc = quickKernel(nums, start, end)
if loc == k:
return nums[loc]
elif loc < k:
start = loc + 1
else:
end = loc - 1
def quickKernel(nums, start, end):
low = start
high = end
base = nums[start]
while low < high:
while low < high and nums[high] >= base:
high -= 1
nums[low] = nums[high]
while low < high and nums[low] < base:
low += 1
nums[high] = nums[low]
nums[low] = base
return low
def solve(nums, k):
n = len(nums)
build_heap(nums, n)
for i in range(n-1, n-k-1, -1):
nums[i], nums[0] = nums[0], nums[i]
heapify(nums, i, 0)
return nums[n-k]
def build_heap(nums, n):
i = n // 2
while i >= 0:
heapify(nums, n, i)
i -= 1
def heapify(nums, n, i):
left = 2 * i
right = 2 * i + 1
largest = i
if left < n and nums[left] > nums[i]:
largest = left
if right < n and nums[right] > nums[largest]:
largest = right
if largest != i:
nums[largest], nums[i] = nums[i], nums[largest]
heapify(nums, n, largest)
-
快排
def quickSort(nums, low, high):
if low >= high:
return nums
loc = kernel(nums, low, high)
quickSort(nums, low, loc-1)
quickSort(nums, loc+1, high)
def kernel(nums, start, end):
low = start
high = end
base = nums[start]
while low < high:
while low < high and nums[high] >= base:
high -= 1
nums[low] = nums[high]
while low < high and nums[low] <= base:
low += 1
nums[high] = nums[low]
nums[low] = base
return low
-
剑指offer40:最小的k个数
# 快排 (时间复杂度期望为o(n))
def quickSort_kernel(arr, start, end):
# if start > end:
# return
base = arr[start]
low = start
high = end
while low < high:
while low < high and arr[high] >= base: # 若是最大的改这里
high -= 1
arr[low] = arr[high]
while low < high and arr[low] <= base: # 若是最大的改这里
low += 1
arr[high] = arr[low]
arr[low] = base
return low
def solve(arr, k):
if k > len(arr) or k <= 0:
return []
start = 0
end = len(arr) - 1
loc = quickSort_kernel(arr, start, end)
while loc != k-1:
# loc = quickSort_kernel(arr, start, end)
if loc > k - 1:
end = loc - 1
else:
start = loc + 1
loc = quickSort_kernel(arr, start, end)
return arr[:k]
# 堆排序
def getLeastNumbers(arr,k):
if k == 0 or k > len(arr) or k < 0:
return []
data = arr[:k]
build_heap(data,len(data)) ##实现
for each in arr[k:]:
if data[0] > each:
data[0] = each
heapify(data,len(data),0)
return data
def build_heap(arr,n):
i = n // 2
while i >= 0:
heapify(arr,n,i)
i -= 1
def heapify(arr,n,i):
left = 2 * i
right = 2 * i + 1
largest = i
if left < n and arr[left] > arr[i]:
largest = left
if right < n and arr[right] > arr[largest]:
largest = right
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i]
heapify(arr,n,largest)
-
LC703:数据流中第k大元素
class Heap:
def __init__(self,desc=False):
"""
初始化,默认创建一个小顶堆
"""
self.heap = []
self.desc = desc
@property
def size(self):
return len(self.heap)
def top(self):
if self.size:
return self.heap[0]
return None
def push(self,item):
"""
添加元素
第一步,把元素加入到数组末尾
第二步,把末尾元素向上调整
"""
self.heap.append(item)
self._sift_up(self.size-1)
def pop(self):
"""
弹出堆顶
第一步,记录堆顶元素的值
第二步,交换堆顶元素与末尾元素
第三步,删除数组末尾元素
第四步,新的堆顶元素向下调整
第五步,返回答案
"""
item = self.heap[0]
self._swap(0,self.size-1)
self.heap.pop()
self._sift_down(0)
return item
def _smaller(self,lhs,rhs):
return lhs > rhs if self.desc else lhs < rhs
def _sift_up(self,index):
"""
向上调整
如果父节点和当前节点满足交换的关系
(对于小顶堆是父节点元素更大,对于大顶堆是父节点更小),
则持续将当前节点向上调整
"""
while index:
parent = (index-1) // 2
if self._smaller(self.heap[parent],self.heap[index]):
break
self._swap(parent,index)
index = parent
def _sift_down(self,index):
"""
向下调整
如果子节点和当前节点满足交换的关系
(对于小顶堆是子节点元素更小,对于大顶堆是子节点更大),
则持续将当前节点向下调整
"""
# 若存在子节点
while index*2+1 < self.size:
smallest = index
left = index*2+1
right = index*2+2
if self._smaller(self.heap[left],self.heap[smallest]):
smallest = left
if right < self.size and self._smaller(self.heap[right],self.heap[smallest]):
smallest = right
if smallest == index:
break
self._swap(index,smallest)
index = smallest
def _swap(self,i,j):
self.heap[i],self.heap[j] = self.heap[j],self.heap[i]
class KthLargest:
def __init__(self, k: int, nums: List[int]):
self.heap = Heap()
self.k = k
for num in nums:
self.heap.push(num)
if self.heap.size > k:
self.heap.pop()
def add(self, val: int) -> int:
self.heap.push(val)
if self.heap.size > self.k:
self.heap.pop()
return self.heap.top()
-
LC414:第三大的数
# a最大 b次大 c第三大
def solve(nums):
a, b, c = float('-inf'), float('-inf'), float('-inf')
for each in nums:
if each > a:
a, b, c = each, a, b
elif each > b and each < a:
b, c = each, b
elif each > c and each < b:
c = each
if c == float('-inf'):
return a
else:
return c
-
LC4:两个正序数组的中位数
def solve(nums1, nums2):
def kernel(k):
index1, index2 = 0, 0
while True:
if index1 == m:
return nums2[index2+k-1]
if index2 == n:
return nums1[index1+k-1]
if k == 1:
return min(nums1[index1], nums2[index2])
newIndex1 = min(index1 + k//2 -1, m-1)
newIndex2 = min(index2 + k//2 -1, n-1)
pivot1, pivot2 = nums1[newIndex1], nums2[newIndex2]
if pivot1 <= pivot2:
k = k - (newIndex1 - index1 + 1)
index1 = newIndex1 + 1
else:
k = k- (newIndex2 - index2 + 1)
index2 = newIndex2 + 1
m, n = len(nums1), len(nums2)
totalLength = m + n
if totalLength % 2 == 1:
return kernel((totalLength+1)//2)
else:
return (kernel(totalLength//2) + kernel(totalLength//2+1)) / 2
回溯
-
LC79【单词搜索】
class Solution:
def exist(self, board: List[List[str]], word: str) -> bool:
m, n = len(board), len(board[0])
def dfs(i, j, k):
if not 0 <= i < m or not 0 <= j < n or board[i][j] != word[k]:
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
-
LC46:全排列【不包含重复数字】
# 回溯
def solve(nums):
n = len(nums)
res = []
def back(first):
if first == n:
res.append(nums[:])
for i in range(first, n):
nums[i], nums[first] = nums[first], nums[i]
back(first+1)
nums[i], nums[first] = nums[first], nums[i]
back(0)
return res
-
LC47:全排列2【包含重复数字】
# 回溯2【含重复数字】
def solve(nums):
res = []
n = len(nums)
used = [0] * n
def back(nums, used, path):
if len(path) == n:
res.append(path[:])
# return
for i in range(n):
if not used[i]:
if i > 0 and nums[i] == nums[i-1] and not used[i-1]:
continue
used[i] = 1
path.append(nums[i])
back(nums, used, path)
used[i] = 0
path.pop()
back(sorted(nums), used, [])
return res
-
LC77:组合
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
def solve(n, k):
res = []
path = []
def back(i):
d = k - len(path)
if d == 0:
res.append(path[:])
return
for j in range(i, d-1, -1):
path.append(j)
back(j-1)
path.pop()
back(n)
return res
-
LC77:组合
-
# zuhe def solve(nums, k): res, path = [], [] n = len(nums) def back(i): d = k - len(path) if d == 0: res.append(path[:]) return for j in range(i, d-1, -1): path.append(nums[j-1]) back(j-1) path.pop() back(n) return res
-
LC39:组合总和
def solve(candidates, target):
res = []
n = len(candidates)
path = []
def back(begin, target):
if target < 0:
return
if target == 0:
res.append(path[:])
return
for i in range(begin, n):
target -= candidates[i]
path.append(candidates[i])
back(i, target)
target += candidates[i]
path.pop()
back(0, target)
return res
def solve(candidates, target):
res, path = [], []
dfs(candidates, target, 0, res, path)
return res
def dfs(nums, target, index, res, path):
if target < 0:
return
if target == 0:
res.append(path[:])
return
for i in range(index, len(nums)):
dfs(nums, target-nums[i], i, res, path+[nums[i]])
-
LC90:子集2【可能含有重复值】
力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
def solve(nums, target):
res, path = [], []
nums.sort() # 不sort的话会有重复值
dfs(nums, 0, res, path, target)
return res
def dfs(nums, index, res, path, target):
if sum(path[:]) == target:
res.append(path[:])
for i in range(index, len(nums)):
if i > index and nums[i] == nums[i-1]:
continue
path.append(nums[i])
dfs(nums, i+1, res, path, target)
path.pop()
-
LC:112路径总和
# 递归
def solve(root, target):
if not root:
return False
if not root.left and not root.right:
return root.val == target
return solve(root.left, target-root.val) or solve(root.right, target-root.val)
# 回溯
def solve(root, target):
if not root:
return False
res = []
return dfs(root, target, res, [root.val])
def dfs(root, target, res, path):
if not root:
return False
if sum(path) == target and not root.left and not root.right:
return True
left_flag, right_flag = False, False
if root.left:
left_flag = dfs(root.left, target, res, path+[root.left.val])
if root.right:
right_flag = dfs(root.right, target, res, path+[root.right.val])
return left_flag or right_flag
-
LC113:路径总和2
def solve(root, target):
res = []
path = []
dfs(root, target, res, path)
return res
def dfs(root, target, res, path):
if not root:
return
path.append(root.val)
target = target - root.val
if not root.left and not root.right and target == 0:
res.append(path[:])
dfs(root.left, target, res, path)
dfs(root.right, target, res, path)
path.pop()
二叉树
-
LC124【二叉树的最大路径和】
# 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 maxPathSum(self, root: Optional[TreeNode]) -> int:
ans = float('-inf')
def dfs(root):
nonlocal ans
if not root:
return 0
left = dfs(root.left)
right = dfs(root.right)
ans = max(ans, left + right + root.val)
return max(max(left, right) + root.val, 0)
dfs(root)
return ans
-
LC236:二叉树的最近公共祖先
def solve(root, p, q):
if not root or root == p or root == q:
return root
left = solve(root.left, p, q)
right = solve(root.right, p, q)
if not left:
return right
if not right:
return left
return root
-
LC235:二叉搜索树的最近公共祖先
def solve(root, p, q):
res = root
while True:
if p.val < res.val and q.val < res.val:
res = res.left
elif p.val > res.val and q.val > res.val:
res = res.right
else:
break
return res
-
LC94:二叉树的中序遍历
# 递归
def solve(root):
res = []
def dfs(root):
if not root:
return None
dfs(root.left)
res.append(root.val)
dfs(root.right)
dfs(root)
return res
# 迭代
def solve(root):
res = []
quene = []
while quene or root:
while root:
quene.append(root)
root = root.left
root = quene.pop()
res.append(root.val)
root = root.right
return res
图
-
LC433【最小基因变化】
class Solution:
def minMutation(self, startGene: str, endGene: str, bank: List[str]) -> int:
if startGene == endGene:
return 0
bank = set(bank)
if endGene not in bank:
return -1
quene = [(startGene, 0)]
while quene:
cur, step = quene.pop(0)
for i, x in enumerate(cur):
for y in 'ACGT':
if y != x:
nxt = cur[:i] + y + cur[i+1:]
if nxt in bank:
if nxt == endGene:
return step + 1
bank.remove(nxt)
quene.append((nxt, step+1))
return -1
-
LC210【课程表2】
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
edges = collections.defaultdict(list)
visited = [0] * numCourses
result = []
valid = True
for each in prerequisites:
edges[each[1]].append(each[0])
def dfs(u):
nonlocal valid
visited[u] = 1
for v in edges[u]:
if visited[v] == 0:
dfs(v)
if not valid:
return
elif visited[v] == 1:
valid = False
return
visited[u] = 2
result.append(u)
for i in range(numCourses):
if valid and not visited[i]:
dfs(i)
if not valid:
return []
return result[::-1]
-
LC207【课程表】
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
edges = collections.defaultdict(list)
visited = [0] * numCourses
result = []
valid = True
for each in prerequisites:
edges[each[1]].append(each[0])
def dfs(u):
nonlocal valid
visited[u] = 1
for v in edges[u]:
if visited[v] == 0:
dfs(v)
if not valid:
return
elif visited[v] == 1:
valid = False
return
visited[u] = 2
result.append(u)
for i in range(numCourses):
if valid and not visited[i]:
dfs(i)
return valid
-
LC130【被围绕的区域】
class Solution:
def solve(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
row, col = len(board), len(board[0])
def dfs(i, j):
board[i][j] = 'B'
for x, y in [(i-1, j), (i+1, j), (i, j-1), (i, j+1)]:
if 0 < x < row and 0 < y < col and board[x][y] == 'O':
dfs(x, y)
for i in range(col):
if board[0][i] == 'O':
dfs(0, i)
if board[row-1][i] == 'O':
dfs(row-1, i)
for i in range(row):
if board[i][0] == 'O':
dfs(i, 0)
if board[i][col-1] == "O":
dfs(i, col-1)
for i in range(row):
for j in range(col):
if board[i][j] == 'O':
board[i][j] = 'X'
if board[i][j] == 'B':
board[i][j] = "O"
-
LC797:所有可能路径
def solve(graph):
path = []
res = []
def back(x):
if x == len(graph) - 1:
res.append(path[:])
for y in graph[x]:
path.append(y)
back(y)
path.pop()
path.append(0)
back(0)
return res
-
LC210、LC207 课程表
def solve(num, condition):
edges = collections.defaultdict(list)
visited = [0] * num
valid = True
result = []
for info in condition:
edges[info[1]].append(info[0])
def dfs(u):
nonlocal valid
visited[u] = 1
for v in edges[u]:
if visited[v] == 0:
dfs(v)
if not valid:
return
elif visited[v] == 1:
valid = False
return
visited[u] = 2
result.append(u)
for i in range(num):
if valid and not visited[i]:
dfs(i)
if not valid:
res = []
else:
res = result[::-1]
return res, valid
-
LC1514:概率最大的路径【无向加权图】
def solve(n, edges, succProb, start, end):
graph = collections.defaultdict(list)
for i, (x, y) in enumerate(edges):
graph[x].append((succProb[i], y))
graph[y].append((succProb[i], x))
quene = [(-1.0, start)]
prob = [0.0] * n
prob[start] = 1.0
while quene:
p, node = quene.pop(0)
p = -p
if p < prob[node]:
continue
for p_next, node_next in graph[node]:
if prob[node_next] < prob[node] * p_next:
prob[node_next] = prob[node] * p_next
quene.append((-prob[node_next], node_next))
return prob[end]
-
LC1971:寻找图中是否存在路径
def solve(n, edges, source, destination):
graph = [[] * n for i in range(n)]
for edge in edges:
x, y = edge[0], edge[1]
graph[x].append(y)
graph[y].append(x)
visited = [0] * n
quene = [source]
visited[source] = 1
while quene:
node = quene.pop(0)
if node == destination:
break
for each in graph[node]:
if not visited[each]:
quene.append(each)
visited[each] = 1
if visited[destination] == 1:
res = True
else:
res = False
return res
哈希表
1、LC128【最长连续序列】
class Solution:
def longestConsecutive(self, nums: List[int]) -> int:
n = len(nums)
dic = set(nums)
res = 0
for each in nums:
if each - 1 not in dic:
cur_len = 1
while (each + 1) in dic:
cur_len += 1
each += 1
res = max(res, cur_len)
return res
区间
1、LC228【汇总区间】
class Solution:
def summaryRanges(self, nums: List[int]) -> List[str]:
res = []
i = 0
n = len(nums)
while i < n:
start = i
while i < n - 1 and nums[i] + 1 == nums[i+1]:
i += 1
s = str(nums[start])
if start < i:
s += '->' + str(nums[i])
res.append(s)
i += 1
return res
2、LC56【合并区间】
class Solution:
def merge(self, intervals: List[List[int]]) -> List[List[int]]:
intervals.sort(key = lambda x:x[0])
n = len(intervals)
i = 0
res = []
while i < n:
left, right = intervals[i]
while i < n - 1 and right >= intervals[i + 1][0]:
right = max(right, intervals[i + 1][1])
i += 1
res.append([left, right])
i += 1
return res
3、LC57【插入区间】
class Solution:
def insert(self, intervals: List[List[int]], newInterval: List[int]) -> List[List[int]]:
res = []
n = len(intervals)
start, end = newInterval
i = 0
while i < n and intervals[i][1] < start:
res.append(intervals[i])
i += 1
while i < n and intervals[i][0] <= end:
start = min(start, intervals[i][0])
end = max(end, intervals[i][1])
i += 1
res.append([start, end])
while i < n:
res.append(intervals[i])
i += 1
return res
4、LC452【最少数量的箭射气球】
class Solution:
def findMinArrowShots(self, points: List[List[int]]) -> int:
points.sort(key = lambda x:x[1])
pos = points[0][1]
res = 1
for each in points:
if each[0] > pos:
pos = each[1]
res += 1
return res
分治
1. LC108【将有序数组转换为二叉搜索树】
# 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]:
return self.kernel(nums, 0, len(nums) - 1)
def kernel(self, nums, left, right):
if left > right:
return None
mid = (left + right) // 2
res = TreeNode(nums[mid])
res.left = self.kernel(nums, left, mid - 1)
res.right = self.kernel(nums, mid + 1, right)
return res
二分法
1. LC35【搜索插入位置】
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
n = len(nums)
res = n
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] >= target:
right = mid - 1
res = mid
else:
left = mid + 1
return res
2. LC74【搜索二维矩阵】
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
m, n = len(matrix), len(matrix[0]) - 1
x, y = 0, n
while x < m and y >= 0:
if target == matrix[x][y]:
return True
elif target < matrix[x][y]:
y -= 1
else:
x += 1
return False
3. LC34【在排序数组中查找元素的起始和结束位置】
class Solution:
def searchRange(self, nums: List[int], target: int) -> List[int]:
def findLeft(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
if mid == 0 or nums[mid - 1] < target:
return mid
else:
right = mid - 1
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
def findright(nums, target):
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
if mid == len(nums) - 1 or nums[mid + 1] > target:
return mid
else:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return -1
return [findLeft(nums, target), findright(nums, target)]
数学
1. LC50【x的指数幂】
class Solution:
def myPow(self, x: float, n: int) -> float:
def kernel(N):
if N == 0:
return 1
y = kernel(N // 2)
return y * y if N % 2 == 0 else y * y * x
return kernel(n) if n >= 0 else 1 / kernel(-n)