题目list【力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台】
LC300:最长上升子序列【【LeetCode】最长上升子序列 python ★★★★★★_yingzoe的博客-CSDN博客_最长上升子序列python】
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
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]
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]
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]
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
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
剑指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
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
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)
山峰数组最大值索引
def solve(nums):
low, high = 0, len(nums)-1
ans = 0
while low <= high:
mid = (low + high) // 2
if nums[mid] > nums[mid+1]:
high = mid - 1
ans = mid
else:
low = mid + 1
return nums[ans]
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
# 堆排(时间复杂度nlogn)
def heapify(arr, n, i):
"""
arr:数组
n:数组的长度
i: 当前节点的索引
"""
r = 2*i + 1
l = 2*i
# 判断左子节点是否大于当前节点
largest = i
if l < n and arr[l] > arr[i]: #降序改为arr[l] < arr[i]
largest = l
# else:
# largest = i
# 判断右子节点是否大于当前节点
if r < n and arr[r] > arr[largest]: #降序改为arr[r] < arr[largest]
largest = r
# 不满足特性,交换节点位置,交换后再次进行heapify
if largest != i:
arr[i], arr[largest] = arr[largest], arr[i]
heapify(arr, n, largest)
def build_max_heaps(arr, n):
i = n//2
# count = 0
while i >= 0:
heapify(arr, n, i)
i -= 1
def heapSort(nums, k):
n = len(nums)
build_max_heaps(nums, n)
for k in range(n-1, n-k-1, -1):
nums[k], nums[0] = nums[0], nums[k]
heapify(nums, k, 0)
return nums[k]
快排
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
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
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()
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
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