前言
继续leetcode刷题生涯
这里记录的都是笔者觉得有点意思的做法
参考了好几位大佬的题解,尤其是powcai大佬和labuladong大佬,感谢各位大佬
321. 拼接最大数
# 单调栈
class Solution:
def maxNumber(self, nums1: List[int], nums2: List[int], k: int) -> List[int]:
# 求出单个数组可以组成i位的最大数组
def getMaXArr(nums, i):
if not i:
return []
# pop表示最多可以不要nums里几个数字,要不组成不了i位数字
stack, pop = [], len(nums) - i
for num in nums:
while pop and stack and stack[-1] < num:
pop -= 1
stack.pop()
stack.append(num)
return stack[:i]
def merge(tmp1, tmp2):
return [max(tmp1, tmp2).pop(0) for _ in range(k)]
res = [0] * k
for i in range(k + 1):
if i <= len(nums1) and k - i <= len(nums2):
# 取num1的i位, num2的k - i
tmp1 = getMaXArr(nums1, i)
tmp2 = getMaXArr(nums2, k - i)
# 合并
tmp = merge(tmp1, tmp2)
if res < tmp:
res = tmp
return res
# 上面一个可以一句话写成
# return max(merge(getMaXArr(nums1, i), getMaXArr(nums2, k - i)) for i in range(k + 1) if i <= len(nums1) and k - i <= len(nums2))
322. 零钱兑换
# 动态规划
class Solution:
def coinChange(self, coins: List[int], amount: int) -> int:
# 自底向上
# dp[i] 表示金额为i需要最少的硬币
# dp[i] = min(dp[i], dp[i - coins[j]]) j所有硬币
dp = [float("inf")] * (amount + 1)
dp[0] = 0
for i in range(1, amount + 1):
dp[i] = min(dp[i - c] if i - c >= 0 else float("inf") for c in coins) + 1
return dp[-1] if dp[-1] != float("inf") else -1
324. 摆动排序 II
# 排序,截断,穿插
class Solution:
def wiggleSort(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
nums.sort(reverse=True)
mid = len(nums) // 2
nums[1::2],nums[0::2] = nums[:mid], nums[mid:]
326. 3的幂
# 递归
class Solution:
def isPowerOfThree(self, n: int) -> bool:
return n > 0 and (n == 1 or (n % 3 == 0 and self.isPowerOfThree(n // 3)))
# 迭代
class Solution:
def isPowerOfThree(self, n: int) -> bool:
if n > 1:
while n % 3 == 0:
n //= 3
return n == 1
327. 区间和的个数
# 前缀树
import bisect
class Solution:
def countRangeSum(self, nums: List[int], lower: int, upper: int) -> int:
p = [0] #前缀和初始化,前缀和p[x],就是区间数组[0, x)的和
for i in nums:
p += [p[-1] + i] #前缀和计算
ans = 0
q = [] #有序的前缀和队列
for pi in p[:: -1]: #逆序遍历前缀和
i, j = pi + lower, pi + upper #给出当前前缀和两个对应边界
l = bisect.bisect_left(q, i) #二分查找
r = bisect.bisect_right(q, j) #找到对应边界的在前缀和数组里的插入位置
ans += r - l #序号大于自己的前缀和里有多少个前缀和在边界里面,就是以当前区间为起点,符合区间和条件的个数
bisect.insort(q, pi) #二分插入更新队列
return ans
328. 奇偶链表
class Solution:
def oddEvenList(self, head: ListNode) -> ListNode:
if not head or not head.next:
return head
odd = head
even = head.next
# 偶链表的排头拿出来
evenHead = even
while even and even.next:
odd.next = odd.next.next
even.next = even.next.next
odd = odd.next
even = even.next
# 奇链表最后一个和偶数排头连起来
odd.next = evenHead
return head
329. 矩阵中的最长递增路径
# dfs
class Solution:
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
if not matrix or not matrix[0]: return 0
row = len(matrix)
col = len(matrix[0])
lookup = [[0] * col for _ in range(row)]
def dfs(i, j):
if lookup[i][j] != 0:
return lookup[i][j]
lookup[i][j] = 1 + max(dfs(i + x, y + j) for x, y in [[-1, 0], [1, 0], [0, 1], [0, -1]] \f 0 <= (i + x) < row and 0 <= (j + y) < col and matrix[i + x][j + y] > matrix[i][j]] or [0])
return lookup[i][j]
return max(dfs(i, j) for i in range(row) for j in range(col))
330. 按要求补齐数组
# 贪心
class Solution:
def minPatches(self, nums: List[int], n: int) -> int:
add, i, count = 1, 0, 0
while add <= n:
if i < len(nums) and nums[i] <= add:
add += nums[i] # from [1, add] to [1, add + nums[i]]
i += 1
else:
add += add # from [1, add] to [1, 2add]
count += 1
return count