468. 验证IP地址
class Solution:
def validIPAddress(self, queryIP: str) -> str:
def isIPv4(ip: str) -> bool:
return all(s and s.isdigit() and not(s[0] == '0' and len(s) > 1) and 0 <= int(s) <= 255 for s in sp) if len(sp := ip.split(".")) == 4 else False
def isIPv6(ip: str) -> bool:
return all(s and len(s) <= 4 and all(c in "0123456789ABCDEFabcdef" for c in s) for s in sp) if len(sp := ip.split(":")) == 8 else False
if "." in queryIP and ":" not in queryIP and isIPv4(queryIP):
return "IPv4"
elif ":" in queryIP and "." not in queryIP and isIPv6(queryIP):
return "IPv6"
return "Neither"
560. 和为 K 的子数组
class Solution:
def subarraySum(self, nums: List[int], k: int) -> int:
s = 0; res = 0
# # 哨兵,起始边界条件
d = defaultdict(int); d[0] = 1
for num in nums:
s += num
res += d[s-k]
d[s] += 1
return res
# 一维前缀和
# 前缀和 + hash表
# s[i] = s[i-1] + num[i]
# 找使 s[i] - s[j] == k 的 j 的个数
# hash表记录前缀和出现的次数
# 时间复杂度:O(n),其中 n 为数组的长度。我们遍历数组的时间复杂度为 O(n),中间利用哈希表查询删除的复杂度均为 O(1),因此总时间复杂度为 O(n)。
# 空间复杂度:O(n)
138. 复制带随机指针的链表
"""
# Definition for a Node.
class Node:
def __init__(self, x: int, next: 'Node' = None, random: 'Node' = None):
self.val = int(x)
self.next = next
self.random = random
"""
class Solution:
def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]':
if not head: return None
d = dict()
p = head
while p:
d[p] = Node(p.val)
p = p.next
p = head
while p:
d[p].next = d.get(p.next)
d[p].random = d.get(p.random)
p = p.next
return d[head]
209. 长度最小的子数组
class Solution:
def minSubArrayLen(self, target: int, nums: List[int]) -> int:
n = len(nums)
res = n + 1; s = 0
i = j = 0
while j < n:
s += nums[j]
while s >= target:
res = min(res, j - i + 1)
s -= nums[i]
i += 1
j += 1
return res if res != n + 1 else 0
# 时间复杂度:O(n)
# 空间复杂度:O(1)
739. 每日温度
class Solution:
def dailyTemperatures(self, temperatures: List[int]) -> List[int]:
s = []
res = [0] * len(temperatures)
for i, v in enumerate(temperatures):
while s and v > s[-1][1]:
s_i, s_v = s.pop()
res[s_i] = i - s_i
s.append((i, v))
return res
# 1.若栈为空或当日温度小于栈顶温度,则直接入栈
# 2.若当日温度大于栈顶温度,说明栈顶元素升温日找到,将栈顶元素出栈,计算其与当日相差的天数
136. 只出现一次的数字
class Solution:
def singleNumber(self, nums: List[int]) -> int:
res = 0
for num in nums:
res ^= num
return res
498. 对角线遍历
class Solution:
def findDiagonalOrder(self, mat: List[List[int]]) -> List[int]:
res = []
m = len(mat); n = len(mat[0])
for k in range(m+n-1):
if k % 2 == 0:
res += [mat[x][k-x] for x in range(min(m-1,k), max(-1,k-n), -1)]
else:
res += [mat[x][k-x] for x in range(max(0,k-n+1),min(m,k+1))]
return res
剑指 Offer 36. 二叉搜索树与双向链表
"""
# Definition for a Node.
class Node:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
"""
class Solution:
def dfs(self, root: 'Node') -> 'Node':
if not root: return
self.dfs(root.left)
# 双向链表
root.left = self.pre
self.pre.right = root
# 右移指针
self.pre = root
self.dfs(root.right)
def treeToDoublyList(self, root: 'Node') -> 'Node':
if not root: return
self.pre = head = Node()
self.dfs(root)
# 首尾相连
self.pre.right, head.right.left = head.right, self.pre
return head.right
224. 基本计算器
class Solution:
def calculate(self, s: str) -> int:
ops = [1]
sign = 1
res = 0
n = len(s)
i = 0
while i < n:
if s[i] == ' ':
i += 1
elif s[i] == '+':
sign = ops[-1]
i += 1
elif s[i] == '-':
sign = -ops[-1]
i += 1
elif s[i] == '(':
ops.append(sign)
i += 1
elif s[i] == ')':
ops.pop()
i += 1
else:
num = 0
while i < n and s[i].isdigit():
num = num * 10 + ord(s[i]) - ord('0')
i += 1
res += num * sign
return res
剑指 Offer 09. 用两个栈实现队列
class CQueue:
def __init__(self):
self.s1, self.s2 = [], []
def appendTail(self, value: int) -> None:
self.s1.append(value)
def deleteHead(self) -> int:
if not self.s2:
while self.s1: self.s2.append(self.s1.pop())
return self.s2.pop() if self.s2 else -1
# Your CQueue object will be instantiated and called as such:
# obj = CQueue()
# obj.appendTail(value)
# param_2 = obj.deleteHead()
460. LFU 缓存
class Node:
def __init__(self, key, val, pre=None, nex=None, freq=0):
self.pre = pre
self.nex = nex
self.freq = freq
self.val = val
self.key = key
def insert(self, nex):
nex.pre = self
nex.nex = self.nex
self.nex.pre = nex
self.nex = nex
def create_linked_list():
head = Node(0, 0)
tail = Node(0, 0)
head.nex = tail
tail.pre = head
return (head, tail)
class LFUCache:
def __init__(self, capacity: int):
self.capacity = capacity
self.size = 0
self.minFreq = 0
self.freqMap = collections.defaultdict(create_linked_list)
self.keyMap = {}
def delete(self, node):
if node.pre:
node.pre.nex = node.nex
node.nex.pre = node.pre
if node.pre is self.freqMap[node.freq][0] and node.nex is self.freqMap[node.freq][-1]:
self.freqMap.pop(node.freq)
return node.key
def increase(self, node):
node.freq += 1
self.delete(node)
self.freqMap[node.freq][-1].pre.insert(node)
if node.freq == 1:
self.minFreq = 1
elif self.minFreq == node.freq - 1:
head, tail = self.freqMap[node.freq - 1]
if head.nex is tail:
self.minFreq = node.freq
def get(self, key: int) -> int:
if key in self.keyMap:
self.increase(self.keyMap[key])
return self.keyMap[key].val
return -1
def put(self, key: int, value: int) -> None:
if self.capacity != 0:
if key in self.keyMap:
node = self.keyMap[key]
node.val = value
else:
node = Node(key, value)
self.keyMap[key] = node
self.size += 1
if self.size > self.capacity:
self.size -= 1
deleted = self.delete(self.freqMap[self.minFreq][0].nex)
self.keyMap.pop(deleted)
self.increase(node)
912. 排序数组
class Solution:
def sortArray(self, nums: List[int]) -> List[int]:
def merge_sort(a: list, l: int, r: int) -> list:
if l >= r: return a
m = l + r >> 1
i = l; j = m + 1
tmp = []
merge_sort(a, l, m); merge_sort(a, m + 1, r)
while i <= m and j <= r:
if a[i] < a[j]:
tmp.append(a[i])
i += 1
else:
tmp.append(a[j])
j += 1
tmp += a[i:m+1]
tmp += a[j:r+1]
a[l:r+1] = tmp
return a
return merge_sort(nums, 0, len(nums) - 1)
207. 课程表
class Solution:
def canFinish(self, numCourses: int, prerequisites: List[List[int]]) -> bool:
edges = collections.defaultdict(list)
indeg = [0] * numCourses
for info in prerequisites:
edges[info[1]].append(info[0])
indeg[info[0]] += 1
q = collections.deque([u for u in range(numCourses) if indeg[u] == 0])
visited = 0
while q:
visited += 1
u = q.popleft()
for v in edges[u]:
indeg[v] -= 1
if indeg[v] == 0:
q.append(v)
return visited == numCourses
402. 移掉 K 位数字
class Solution:
def removeKdigits(self, num: str, k: int) -> str:
numStack = []
# 构建单调递增的数字串
for digit in num:
while k and numStack and numStack[-1] > digit:
numStack.pop()
k -= 1
numStack.append(digit)
# 如果 K > 0,删除末尾的 K 个字符
finalStack = numStack[:-k] if k else numStack
# 抹去前导零
return "".join(finalStack).lstrip('0') or "0"
958. 二叉树的完全性检验
# 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(object):
def isCompleteTree(self, root):
q = [(root, 1)]
i = 0
while i < len(q):
node, v = q[i]
if node:
q.append((node.left, 2*v))
q.append((node.right, 2*v+1))
i += 1
return q[-1][1] == len(q)
# 时间复杂度:O(N)
# 空间复杂度:O(N)
61. 旋转链表
class Solution:
def rotateRight(self, head: ListNode, k: int) -> ListNode:
# 若链表为空,返回head
if not head:
return head
# 获取链表的长度
n = 0
cur = head
while cur:
n += 1
cur = cur.next
# 若k的长度大于n,将k对n求余
k = k % n
# 若k==0表示循环了一整遍,直接返回head
if k == 0:
return head
# 创建快慢指针
slow = fast = head
# fast指针先走k步
while k:
fast = fast.next
k -= 1
# 让fast指针走到队尾
while fast.next:
fast = fast.next
slow = slow.next
# 此时show.next为新的链表头
h = slow.next
# 断开slow.next
slow.next = None
# 链表首位相接
fast.next = head
# 返回新的链表头
return h
11. 盛最多水的容器
class Solution:
def maxArea(self, height: List[int]) -> int:
res = 0
l = 0; r = len(height) - 1
while l < r:
# 相同条件下边界距离越远,面积越大,所以设置左右指针从两边向中间移动;哪个边界小,哪个边界移动重新寻找机会,希望用边界高度的增加弥补两边界距离的减小
if height[l] < height[r]:
res = max(res, (r - l) * height[l])
l += 1
else:
res = max(res, (r - l) * height[r])
r -= 1
return res
剑指 Offer 54. 二叉搜索树的第k大节点
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
#先尝试中序遍历保存所有节点,再找倒数第k个节点
def inOrder(root):
if not root: return
inOrder(root.left)
self.inorder.append(root.val)
inOrder(root.right)
self.inorder = []
inOrder(root)
return self.inorder[-k]
剑指 Offer 10- II. 青蛙跳台阶问题
class Solution:
def numWays(self, n: int) -> int:
p = 0; q = 1
for i in range(n):
p, q = q, p+q
return q % 1000000007
79. 单词搜索
class Solution(object):
# 定义上下左右四个行走方向
directs = [(0, 1), (0, -1), (1, 0), (-1, 0)]
def exist(self, board, word):
"""
:type board: List[List[str]]
:type word: str
:rtype: bool
"""
m = len(board)
if m == 0:
return False
n = len(board[0])
visited = [[0 for _ in range(n)] for _ in range(m)]
for i in range(len(board)):
for j in range(len(board[0])):
if board[i][j] == word[0]:
# 将该元素标记为已使用
visited[i][j] = 1
if self.backtrack(i, j, visited, board, word[1:]) == True:
return True
else:
# 回溯
visited[i][j] = 0
return False
def backtrack(self, i, j, visited, board, word):
if len(word) == 0:
return True
for direct in self.directs:
cur_i = i + direct[0]
cur_j = j + direct[1]
if cur_i >= 0 and cur_i < len(board) and cur_j >= 0 and cur_j < len(board[0]) and board[cur_i][cur_j] == word[0]:
# 如果是已经使用过的元素,忽略
if visited[cur_i][cur_j] == 1:
continue
# 将该元素标记为已使用
visited[cur_i][cur_j] = 1
if self.backtrack(cur_i, cur_j, visited, board, word[1:]) == True:
return True
else:
# 回溯
visited[cur_i][cur_j] = 0
return False
剑指 Offer 51. 数组中的逆序对
class Solution:
def merge_sort(self, a: list, l: int, r: int) -> int:
if l >= r: return 0
tmp = []
m = l + r >> 1
i = l; j = m + 1
res = self.merge_sort(a, l, m) + self.merge_sort(a, m + 1, r)
while i <= m and j <= r:
if a[i] <= a[j]:
tmp.append(a[i])
i += 1
else:
res += m - i + 1
tmp.append(a[j])
j += 1
tmp += a[i: m + 1]; tmp += a[j: r + 1]
a[l: r + 1] = tmp
return res
def reversePairs(self, nums: List[int]) -> int:
return self.merge_sort(nums, 0, len(nums) - 1)
59. 螺旋矩阵 II
class Solution:
def generateMatrix(self, n: int) -> List[List[int]]:
l, r, t, b = 0, n - 1, 0, n - 1
res = [[0 for _ in range(n)] for _ in range(n)]
num, tar = 1, n * n
while num <= tar:
for i in range(l, r + 1): # left to right
if num <= tar:
res[t][i] = num
num += 1
t += 1
for i in range(t, b + 1): # top to bottom
if num <= tar:
res[i][r] = num
num += 1
r -= 1
for i in range(r, l - 1, -1): # right to left
if num <= tar:
res[b][i] = num
num += 1
b -= 1
for i in range(b, t - 1, -1): # bottom to top
if num <= tar:
res[i][l] = num
num += 1
l += 1
return res
47. 全排列 II
class Solution:
def permuteUnique(self, nums: List[int]) -> List[List[int]]:
res = []
path = []
n = len(nums)
nums.sort()
visited = [False for _ in range(n)]
def backtrace(idx: int) -> None:
if idx == n:
res.append(path[:])
return
for i in range(0, n):
if visited[i] == True or (0 < i and nums[i - 1] == nums[i] and visited[i - 1] == False): continue
path.append(nums[i])
visited[i] = True
backtrace(idx + 1)
path.pop()
visited[i] = False
backtrace(0)
return res
55. 跳跃游戏
class Solution:
def canJump(self, nums: List[int]) -> bool:
end = 0
for i in range(len(nums)):
if i > end: return False
end = max(end, i+nums[i])
return True
40. 组合总和 II
from typing import List
class Solution:
def combinationSum2(self, candidates: List[int], target: int) -> List[List[int]]:
def dfs(begin, path, residue):
if residue == 0:
res.append(path[:])
return
for index in range(begin, size):
if candidates[index] > residue:
break
if index > begin and candidates[index - 1] == candidates[index]:
continue
path.append(candidates[index])
dfs(index + 1, path, residue - candidates[index])
path.pop()
size = len(candidates)
if size == 0:
return []
candidates.sort()
res = []
dfs(0, [], target)
return res
123. 买卖股票的最佳时机 III
class Solution:
def maxProfit(self, prices: List[int]) -> int:
if not prices: return 0
k = 2
n = len(prices)
k = min(k, n // 2)
buy = [0] * (k + 1)
sell = [0] * (k + 1)
buy[0], sell[0] = -prices[0], 0
for i in range(1, k + 1):
buy[i] = sell[i] = float("-inf")
for i in range(1, n):
buy[0] = max(buy[0], sell[0] - prices[i])
for j in range(1, k + 1):
buy[j] = max(buy[j], sell[j] - prices[i])
sell[j] = max(sell[j], buy[j - 1] + prices[i]);
return max(sell)
26. 删除有序数组中的重复项
class Solution:
def removeDuplicates(self, nums: List[int]) -> int:
j = 0
for i in range(len(nums)):
if nums[i] != nums[j]:
j += 1
nums[j] = nums[i]
return j + 1
# 时间复杂度:O(n)
# 空间复杂度:O(1)
剑指 Offer 42. 连续子数组的最大和
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
n = len(nums)
dp = [0] * n
dp[0] = nums[0]
# dp 以下标 i 结尾的最大和的连续子数组
for i in range(1, n):
if dp[i-1] > 0:
dp[i] = dp[i-1] + nums[i]
else:
dp[i] = nums[i]
return max(dp)
50. Pow(x, n)
class Solution:
def myPow(self, x: float, n: int) -> float:
res = 1
if n < 0: n = -n; x = 1 / x
while n:
if n % 2 == 1: res *= x
# if n & 1: res *= x
x = x * x
n //= 2
# n >>= 1
return res
518. 零钱兑换 II
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
# dp[x] 表示金额之和等于 x 的硬币组合数
# 动态规划的边界是 dp[0]=1。只有当不选取任何硬币时,金额之和才为 0,因此只有 1 种硬币组合
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for i in range(coin, amount + 1):
dp[i] += dp[i - coin]
return dp[amount]
145. 二叉树的后序遍历
# 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 postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
def dfs(root: TreeNode):
if root is None: return
dfs(root.left)
dfs(root.right)
res.append(root.val)
res = []
dfs(root)
return res
剑指 Offer 40. 最小的k个数
class Solution:
def getLeastNumbers(self, arr: List[int], k: int) -> List[int]:
def quick_sort(a, l, r):
if l >= r: return a
i = l - 1; j = r + 1
x = a[l + r >> 1]
while i < j:
i += 1
while a[i] < x: i += 1
j -= 1
while a[j] > x: j -= 1
if i < j: a[i], a[j] = a[j], a[i]
quick_sort(a, l, j); quick_sort(a, j + 1, r)
return a
if k >= len(arr): return arr
res = quick_sort(arr, 0, len(arr) - 1)
return res[:k]
7. 整数反转
class Solution:
def reverse(self, x: int) -> int:
res = int((str(x) if x > 0 else str(-x) + "-")[::-1])
return res if -2**31 < res < 2**31 else 0
74. 搜索二维矩阵
class Solution:
def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
row = len(matrix); col = len(matrix[0])
l = 0; r = row * col - 1
while l <= r:
m = l + r >> 1
num = matrix[m//col][m%col]
if num == target:
return True
elif num < target:
l = m + 1
else:
r = m - 1
return False
# 展开成一维数组,全局有序
# 时间复杂度:O(logmn),其中 m 和 n 分别是矩阵的行数和列数。
# 空间复杂度:O(1)
剑指 Offer 10- I. 斐波那契数列
class Solution:
def fib(self, n: int) -> int:
p = 0; q = 1
for i in range(n):
p, q = q, p+q
return p % 1000000007
440. 字典序的第K小数字
class Solution:
def getSteps(self, cur: int, n: int) -> int:
steps, first, last = 0, cur, cur
while first <= n:
steps += min(last, n) - first + 1
first *= 10
last = last * 10 + 9
return steps
def findKthNumber(self, n: int, k: int) -> int:
cur = 1
k -= 1
while k:
steps = self.getSteps(cur, n)
if steps <= k:
k -= steps
cur += 1
else:
cur *= 10
k -= 1
return cur
450. 删除二叉搜索树中的节点
# 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 deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root: return None
if root.val > key: root.left = self.deleteNode(root.left, key) # 去左子树删除
elif root.val < key: root.right = self.deleteNode(root.right, key) # 去右子树删除
# 当前节点就是要删除的节点
else:
if not root.left: return root.right # 当前节点无左子树,不要写成 root = root.right,这样会多走一步报空值异常
if not root.right: return root.left # 当前节点无右子树,不要写成 root = root.left,这样会多走一步报空值异常
else: # 当前节点左右子树都有
node = root.right
while node.left: # 寻找欲删除节点右子树的最左节点
node = node.left
node.left = root.left # 将欲删除节点的左子树成为其右子树最左节点的左子树
root = root.right # 欲删除节点的右子树顶替其位置,节点被删除
return root
# 根据二叉搜索树的性质:
# 1. 如果目标节点大于当前节点值,则去右子树中删除;
# 2. 如果目标节点小于当前节点值,则去左子树中删除;
# 3. 如果目标节点就是当前节点,分为以下三种情况:
# 3.1 其无左子:其右子顶替其位置,删除了该节点;
# 3.2 其无右子:其左子顶替其位置,删除了该节点;
# 3.3 其左右子节点都有:其左子树转移到其右子树的最左节点的左子树上,然后右子树顶替其位置,由此删除了该节点。
# 时间复杂度:O(H),H是树的高度,寻找目标节点最坏情况需要O(H),删除操作最坏情况也需要O(H);
# 空间复杂度:O(H),递归栈的深度最坏情况为树的高度;
剑指 Offer 04. 二维数组中的查找
class Solution:
def findNumberIn2DArray(self, matrix: List[List[int]], target: int) -> bool:
if not matrix: return False
m = len(matrix); n = len(matrix[0])
i = 0; j = n - 1
while i < m and j >= 0:
if matrix[i][j] == target: return True
elif matrix[i][j] < target: i += 1
else: j -= 1
return False
75. 颜色分类
class Solution:
def sortColors(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if len(nums) < 2: return
# 循环不变量确定循环变量
# 0 in [0, p0), 1 in [p0, p1), 2 in [p2, len(nums)]
p1 = 0; p0 = 0; p2 = len(nums) - 1
# 循环变量 p1 > p2 时, 跳出循环
while p1 <= p2:
if nums[p1] == 0: # 0, 1交换,由于交换到右边的是1, 所以根据第二个if条件p1++
nums[p1], nums[p0] = nums[p0], nums[p1]
p0 += 1
p1 += 1
elif nums[p1] == 1:
p1 += 1
else: # nums[p1] == 2
nums[p1], nums[p2] = nums[p2], nums[p1]
# 由于不知道交换回来的nums[p2]的值,所以不对循环变量 p1 操作,进入下一次循环判断
p2 -= 1
# 归并排序思想
剑指 Offer 21. 调整数组顺序使奇数位于偶数前面
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
l = 0; r = len(nums) - 1
while l <= r:
while l <= r and nums[l] % 2 == 1:
l += 1
while l <= r and nums[r] % 2 == 0:
r -= 1
if l > r: break
nums[l], nums[r] = nums[r], nums[l]
return nums
230. 二叉搜索树中第K小的元素
# 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 kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
def dfs(root):
if not root: return
dfs(root.left)
self.res.append(root.val)
dfs(root.right)
self.res = []
dfs(root)
return self.res[k-1]
225. 用队列实现栈
class MyStack:
def __init__(self):
self.q = []
def push(self, x: int) -> None:
n = len(self.q)
self.q.append(x)
for _ in range(n):
self.q.append(self.q.pop(0))
def pop(self) -> int:
return self.q.pop(0)
def top(self) -> int:
return self.q[0]
def empty(self) -> bool:
return not self.q
# Your MyStack object will be instantiated and called as such:
# obj = MyStack()
# obj.push(x)
# param_2 = obj.pop()
# param_3 = obj.top()
# param_4 = obj.empty()
# 入栈操作时,首先获得入栈前的元素个数 nn,然后将元素入队到队列,再将队列中的前 nn 个元素(即除了新入栈的元素之外的全部元素)依次出队并入队到队列,此时队列的前端的元素即为新入栈的元素,且队列的前端和后端分别对应栈顶和栈底。
135. 分发糖果
class Solution:
def candy(self, ratings: List[int]) -> int:
left = [1 for _ in range(len(ratings))]
right = left[:]
for i in range(1, len(ratings)):
if ratings[i] > ratings[i - 1]: left[i] = left[i - 1] + 1
count = left[-1]
for i in range(len(ratings) - 2, -1, -1):
if ratings[i] > ratings[i + 1]: right[i] = right[i + 1] + 1
count += max(left[i], right[i])
return count
剑指 Offer 62. 圆圈中最后剩下的数字
class Solution:
def lastRemaining(self, n: int, m: int) -> int:
f = 0
for i in range(2, n+1):
# dp[n,m] = 0 n = 1
# dp[n,m] = (dp[n-1,m] + m) % n n > 1
f = (f + m) % i
return f
45. 跳跃游戏 II
class Solution:
def jump(self, nums: List[int]) -> int:
res = 0
end = max_v = 0
for i in range(len(nums)-1):
max_v = max(max_v, i+nums[i])
if i == end:
end = max_v
res += 1
return res
# 1.维护几个变量:当前所能达到的最远位置 end,下一步所能跳到的最远位置 max_pos,最少跳跃次数 setps。
# 2.遍历数组 nums 的前 len(nums) - 1 个元素:
# 每次更新第 i 位置下一步所能跳到的最远位置 max_pos。
# 如果索引 i 到达了 end 边界,则:更新 end 为新的当前位置 max_pos,并令步数 setps 加 1。
# 3.最终返回跳跃次数 steps。
# 时间复杂度:O(n)O(n)。一重循环遍历的时间复杂度是 O(n)O(n),所以总体时间复杂度为 O(n)O(n)。
# 空间复杂度:O(1)O(1)。只用到了常数项的变量,所以总体空间复杂度为 O(1)O(1)。
91. 解码方法
class Solution:
def numDecodings(self, s: str) -> int:
n = len(s)
dp = [1] + [0] * n
for i in range(1, n + 1):
if s[i - 1] != '0':
dp[i] += dp[i - 1]
if i > 1 and s[i - 2] != '0' and int(s[i-2:i]) <= 26:
dp[i] += dp[i - 2]
return dp[n]
329. 矩阵中的最长递增路径
class Solution:
def longestIncreasingPath(self, matrix: List[List[int]]) -> int:
if not matrix:
return 0
h,w = len(matrix),len(matrix[0])
store = [[None]*(w) for i in range(h)]
m = 0 #储存max路径值
def search_nearby(i,j):
nonlocal m
compare = [] #储存可以比较的候选人
#这个楼主很懒,还没想怎么简化下面的代码
#反正下面四个代码块就是分别看一下上、下、左、右哪些格子的值可以当做候选人比较
#上
if i != 0 and matrix[i-1][j] < matrix[i][j]: #有上边且上边小于当前数的话
compare.append(store[i-1][j]) if store[i-1][j] else compare.append(search_nearby(i-1,j))
#左
if j != 0 and matrix[i][j-1] < matrix[i][j]: #有左边且左边小于当前数的话
compare.append(store[i][j-1]) if store[i][j-1] else compare.append(search_nearby(i,j-1))
#下
if i != h-1 and matrix[i+1][j] < matrix[i][j]: #有下边且下边小于当前数的话
compare.append(store[i+1][j]) if store[i+1][j] else compare.append(search_nearby(i+1,j))
#右
if j != w-1 and matrix[i][j+1] < matrix[i][j]: #有右边且右边小于当前数的话
compare.append(store[i][j+1]) if store[i][j+1] else compare.append(search_nearby(i,j+1))
store[i][j] = max(compare)+1 if compare else 1
#如果没有compare说明这是一个很小的数,是一个起始点,能组成的长度只有1
#有的话就原来最长路径+1
m = max(m,store[i][j])
return (store[i][j])
for i in range(h):
for j in range(w):
if not store[i][j]:
search_nearby(i,j)
return m
572. 另一棵树的子树
# 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 dfs(self, p, q):
if not p and not q: return True
if not p or not q: return False
return p.val == q.val and self.dfs(p.left, q.left) and self.dfs(p.right, q.right)
def isSubtree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool:
if not root and not subRoot: return True
if not root or not subRoot: return False
return self.dfs(root, subRoot) or self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)
328. 奇偶链表
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def oddEvenList(self, head: Optional[ListNode]) -> Optional[ListNode]:
if not head:
return head
odd = head; even = evenHead = head.next
while even and even.next:
odd.next = even.next
odd = odd.next
even.next = odd.next
even = even.next
odd.next = evenHead
return head
114. 二叉树展开为链表
# 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 flatten(self, root: Optional[TreeNode]) -> None:
"""
Do not return anything, modify root in-place instead.
"""
res = []
def dfs(root):
if root is None: return
res.append(root)
dfs(root.left)
dfs(root.right)
dfs(root)
for i in range(1, len(res)):
pre, cur = res[i-1], res[i]
pre.left = None
pre.right = cur
# 前序遍历
# 时间复杂度:O(n)
# 空间复杂度:O(n)
208. 实现 Trie (前缀树)
class Trie:
def __init__(self):
self.children = [None] * 26
self.isEnd = False
def searchPrefix(self, prefix: str) -> "Trie":
node = self
for ch in prefix:
ch = ord(ch) - ord("a")
if not node.children[ch]:
return None
node = node.children[ch]
return node
def insert(self, word: str) -> None:
node = self
for ch in word:
ch = ord(ch) - ord("a")
if not node.children[ch]:
node.children[ch] = Trie()
node = node.children[ch]
node.isEnd = True
def search(self, word: str) -> bool:
node = self.searchPrefix(word)
return node is not None and node.isEnd
def startsWith(self, prefix: str) -> bool:
return self.searchPrefix(prefix) is not None
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
9. 回文数
class Solution:
def isPalindrome(self, x: int) -> bool:
return str(x) == str(x)[::-1]
剑指 Offer 26. 树的子结构
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
#1.先序遍历树A中的每个节点, 2.再判断A中每个节点是否包含B
class Solution:
#子结构
def isSubStructure(self, A: TreeNode, B: TreeNode) -> bool:
#包含
def dfs(A: TreeNode, B: TreeNode) -> bool:
# 当节点B为空:说明树B已匹配完成(越过叶子节点),因此返回True;
if not B: return True
# 当节点A为空:说明已经越过树A叶子节点,即匹配失败,返回False;
# 当节点A和B的值不同:说明匹配失败,返回False;
if not A or A.val != B.val: return False
return dfs(A.left,B.left) and dfs(A.right,B.right)
if not A or not B: return False
return dfs(A,B) or self.isSubStructure(A.left, B) or self.isSubStructure(A.right, B)
189. 轮转数组
class Solution:
def rotate(self, nums: List[int], k: int) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
n = len(nums)
k %= n
tmp = nums[-k:] + nums[:-k]
nums[:] = tmp[:]
384. 打乱数组
class Solution:
def __init__(self, nums: List[int]):
self.nums = nums
self.original = nums.copy()
def reset(self) -> List[int]:
self.nums = self.original.copy()
return self.nums
def shuffle(self) -> List[int]:
for i in range(len(self.nums)):
j = random.randrange(i, len(self.nums))
self.nums[i], self.nums[j] = self.nums[j], self.nums[i]
return self.nums
# Your Solution object will be instantiated and called as such:
# obj = Solution(nums)
# param_1 = obj.reset()
# param_2 = obj.shuffle()
125. 验证回文串
class Solution:
def isPalindrome(self, s: str) -> bool:
# isalnum() 方法检测字符串是否由字母和数字组成。
t = ''.join(c.lower() for c in s if c.isalnum())
return t == t[::-1]
10. 正则表达式匹配
class Solution:
def isMatch(self, s: str, p: str) -> bool:
m, n = len(s), len(p)
def matches(i: int, j: int) -> bool:
if i == 0:
return False
if p[j - 1] == '.':
return True
return s[i - 1] == p[j - 1]
dp = [[False] * (n + 1) for _ in range(m + 1)]
dp[0][0] = True
for i in range(m + 1):
for j in range(1, n + 1):
if p[j - 1] == '*':
dp[i][j] |= dp[i][j - 2]
if matches(i, j - 1):
dp[i][j] |= dp[i - 1][j]
else:
if matches(i, j):
dp[i][j] |= dp[i - 1][j - 1]
return dp[m][n]
295. 数据流的中位数
from sortedcontainers import SortedList
class MedianFinder:
def __init__(self):
self.nums = SortedList()
def addNum(self, num: int) -> None:
self.nums.add(num)
def findMedian(self) -> float:
n = len(self.nums)
return (self.nums[n // 2] + self.nums[(n - 1) // 2]) / 2
# Your MedianFinder object will be instantiated and called as such:
# obj = MedianFinder()
# obj.addNum(num)
# param_2 = obj.findMedian()
445. 两数相加 II
# 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]:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
# 利用栈先进后出实现由低位向高位加
s1, s2 = [], []
while l1:
s1.append(l1.val)
l1 = l1.next
while l2:
s2.append(l2.val)
l2 = l2.next
# 当前指针,结果链表
res = None
# 进位项
carry = 0
# 非空满足循环条件
while s1 or s2 or carry != 0:
n1 = s1.pop() if s1 else 0
n2 = s2.pop() if s2 else 0
n = n1 + n2 + carry
carry = n // 10
cur = ListNode(n % 10)
cur.next = res
res = cur
return res
剑指 Offer 27. 二叉树的镜像
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def mirrorTree(self, root: TreeNode) -> TreeNode:
# 递归函数的终止条件,节点为空时返回
if not root: return None
# 将当前节点的左右子树交换
root.left, root.right = root.right, root.left
# 递归交换当前节点的 左子树和右子树
self.mirrorTree(root.left)
self.mirrorTree(root.right)
# 函数返回时就表示当前这个节点,以及它的左右子树
# 都已经交换完了
return root
16. 最接近的三数之和
class Solution:
def threeSumClosest(self, nums: List[int], target: int) -> int:
res = nums[0] + nums[1] + nums[2]
nums.sort()
for i in range(len(nums)):
l = i + 1; r = len(nums) - 1
while l < r:
sums = nums[i] + nums[l] + nums[r]
if abs(sums-target) < abs(res-target): res = sums
if sums < target: l += 1
elif sums > target: r -= 1
else: return res
return res
287. 寻找重复数
class Solution:
def findDuplicate(self, nums: List[int]) -> int:
slow = 0; fast = 0
while True:
# 先走一步再判断,要不然刚开始就退出了
slow = nums[slow]
fast = nums[nums[fast]]
if slow == fast: break
slow = 0
while slow != fast:
slow = nums[slow]
fast = nums[fast]
return slow
# 转换为图论,之后用 142. 环形链表 II 解法
# 数字都在 [1, n],因此0一定没有环
# 从0开始走一定会走到环里
# 环的入口表示至少有2个数存的环的入口,即重复数
# 时间复杂度:O(n)。Floyd 判圈算法时间复杂度为线性的时间复杂度。
# 空间复杂度:O(1)O(1)
106. 从中序与后序遍历序列构造二叉树
# 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 buildTree(self, inorder: List[int], postorder: List[int]) -> TreeNode:
if not postorder: return None
root = TreeNode(postorder[-1])
cur = inorder.index(root.val)
root.left = self.buildTree(inorder[0:cur], postorder[0:cur])
root.right = self.buildTree(inorder[cur+1:], postorder[cur:-1])
return root
剑指 Offer 29. 顺时针打印矩阵
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
if not matrix: return []
m = len(matrix); n = len(matrix[0])
l = 0; r = n - 1; t = 0; b = m - 1
num = 1; tt = m * n
res = []
while num <= tt:
for i in range(l, r + 1):
if num <= tt:
res.append(matrix[t][i])
num += 1
t += 1
for i in range(t, b + 1):
if num <= tt:
res.append(matrix[i][r])
num += 1
r -= 1
for i in range(r, l - 1, -1):
if num <= tt:
res.append(matrix[b][i])
num += 1
b -= 1
for i in range(b, t - 1, -1):
if num <= tt:
res.append(matrix[i][l])
num += 1
l += 1
return res
96. 不同的二叉搜索树
class Solution:
def numTrees(self, n: int) -> int:
dp = [0] * (n + 1)
dp[0] = 1
for i in range(1, n + 1):
for j in range(1, i+1):
dp[i] += dp[j-1] * dp[i-j]
return dp[n]
# 动态规划,dp[n] 表示整数 n 对应的二叉搜索树种类
# 时间复杂度 : O(n^2),其中 n 表示二叉搜索树的节点个数。
# 空间复杂度 : O(n)
213. 打家劫舍 II
class Solution:
def rob(self, nums: [int]) -> int:
def my_rob(nums):
cur, pre = 0, 0
for num in nums:
cur, pre = max(pre + num, cur), cur
return cur
return max(my_rob(nums[:-1]),my_rob(nums[1:])) if len(nums) != 1 else nums[0]
400. 第 N 位数字
class Solution:
def findNthDigit(self, n: int) -> int:
d, count = 1, 9
while n > d * count:
n -= d * count
d += 1
count *= 10
index = n - 1
start = 10 ** (d - 1)
num = start + index // d
digitIndex = index % d
return num // 10 ** (d - digitIndex - 1) % 10
349. 两个数组的交集
class Solution:
def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
nums1.sort(); nums2.sort()
res = []
p1 = 0; p2 = 0
while p1 < len(nums1) and p2 < len(nums2):
n1 = nums1[p1]; n2 = nums2[p2]
if n1 == n2:
if not res or n1 != res[-1]: res.append(n1)
p1 += 1
p2 += 1
elif n1 < n2:
p1 += 1
else:
p2 += 1
return res
# 排序 + 双指针
# 时间复杂度:O(mlogm+nlogn),其中 m 和 n 分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O(mlogm) 和 O(nlogn),双指针寻找交集元素的时间复杂度是 O(m+n)O(m+n),因此总时间复杂度是O(mlogm+nlogn)。
# 空间复杂度:O(logm+logn),其中 mm 和 nn 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。
120. 三角形最小路径和
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
for i in range(n - 2, -1, -1):
for j in range(len(triangle[i])):
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
return triangle[0][0]
347. 前 K 个高频元素
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
c = collections.Counter(nums)
print(c)
h = []
for key, val in c.items():
heapq.heappush(h, (val, key))
if len(h) > k:
heapq.heappop(h)
return [x[1] for x in h]
887. 鸡蛋掉落
class Solution:
def superEggDrop(self, k: int, n: int) -> int:
if n == 1:
return 1
f = [[0] * (k + 1) for _ in range(n + 1)]
for i in range(1, k + 1):
f[1][i] = 1
res = -1
for i in range(2, n + 1):
for j in range(1, k + 1):
f[i][j] = 1 + f[i - 1][j - 1] + f[i - 1][j]
if f[i][k] >= n:
res = i
break
return res
168. Excel表列名称
class Solution:
def convertToTitle(self, columnNumber: int) -> str:
res = list()
while columnNumber > 0:
columnNumber -= 1
res.append(chr(columnNumber % 26 + ord("A")))
columnNumber //= 26
return "".join(res[::-1])
剑指 Offer 61. 扑克牌中的顺子
class Solution:
def isStraight(self, nums: List[int]) -> bool:
joker = 0
nums.sort() # 数组排序
for i in range(4):
if nums[i] == 0: joker += 1 # 统计大小王数量
elif nums[i] == nums[i + 1]: return False # 若有重复,提前返回 false
return nums[4] - nums[joker] < 5 # 最大牌 - 最小牌 < 5 则可构成顺子
面试题 02.05. 链表求和
# 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]:
dummpy = cur = ListNode()
carry = 0
while l1 or l2 or carry != 0:
n1 = l1.val if l1 else 0
n2 = l2.val if l2 else 0
n = n1 + n2 + carry
carry = n // 10
cur.next = ListNode(n % 10)
if l1: l1 = l1.next
if l2: l2 = l2.next
cur = cur.next
return dummpy.next
678. 有效的括号字符串
class Solution:
def checkValidString(self, s: str) -> bool:
def help(a):
cnt = 0
for c in s if a == 1 else reversed(s):
if c == '(': cnt += a
if c == ')': cnt += -a
if c == '*': cnt += 1
if cnt < 0:
return False
return True
return help(1) and help(-1)
剑指 Offer 52. 两个链表的第一个公共节点
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution:
def getIntersectionNode(self, headA: ListNode, headB: ListNode) -> Optional[ListNode]:
p = headA; q = headB
while p != q:
p = p.next if p else headB
q = q.next if q else headA
return p
111. 二叉树的最小深度
# 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 minDepth(self, root: Optional[TreeNode]) -> int:
if not root: return 0
l = self.minDepth(root.left)
r = self.minDepth(root.right)
if root.left is None or root.right is None: return l + r + 1
return min(l, r) + 1
# 叶子节点的定义是左孩子和右孩子都为 null 时叫做叶子节点
# 当 root 节点左右孩子都为空时,返回 1
# 当 root 节点左右孩子有一个为空时,返回不为空的孩子节点的深度
# 当 root 节点左右孩子都不为空时,返回左右孩子较小深度的节点值
679. 24 点游戏
class Solution:
def judgePoint24(self, cards: List[int]) -> bool:
if len(cards) == 1:
return math.isclose(cards[0], 24)
for _ in range(len(cards)):
a = cards.pop(0) # 摸一张 (queue 操作)
for _ in range(len(cards)):
b = cards.pop(0) # 再摸一张 (queue 操作)
for value in [a + b, a - b, a * b, b and a / b]: # 算一下
cards.append(value) # 记下来 (stack 操作)
if self.judgePoint24(cards):
return True
cards.pop() # (stack 操作)
cards.append(b) # (queue 操作)
cards.append(a) # (queue 操作)
return False
134. 加油站
class Solution:
def canCompleteCircuit(self, gas: List[int], cost: List[int]) -> int:
# 跑完全程再回到起点,总油量剩余值的任意部分都需要在X轴以上; 且跑到终点时:总剩余汽油量 >= 0。
n = len(gas)
cur = 0; minindex= 0; mingas = 0
for i in range(n):
cur += gas[i] - cost[i]
if cur < mingas:
mingas = cur
minindex = i + 1
return -1 if cur < 0 else minindex
1004. 最大连续1的个数 III
class Solution:
def longestOnes(self, nums: List[int], k: int) -> int:
res = 0; cnt = 0; j = 0
for i in range(len(nums)):
if nums[i] == 0: cnt += 1
while cnt > k:
if nums[j] == 0: cnt -= 1
j += 1
res = max(res, i - j + 1)
return res
# 时间复杂度:O(n)
# 空间复杂度:O(1)
611. 有效三角形的个数
class Solution:
def triangleNumber(self, nums: List[int]) -> int:
res = 0
nums.sort()
# k是最短边,j是次短边,i是最长边
# nums[k] + nums[j] > nums[i]
for i in range(2, len(nums)):
j = i - 1; k = 0
while j > 0 and j > k:
while k < j and nums[k] + nums[j] <= nums[i] : k += 1
# [k, j-1]都是最短边的选法,j-1-k+1
res += j - k
j -= 1
return res
# 时间复杂度:O(n*n)
# 空间复杂度:O(logn)
剑指 Offer 39. 数组中出现次数超过一半的数字
class Solution:
def majorityElement(self, nums: List[int]) -> int:
votes = 0
for num in nums:
if votes == 0: x = num
votes += 1 if num == x else -1
return x
673. 最长递增子序列的个数
class Solution:
def findNumberOfLIS(self, nums: List[int]) -> int:
n = len(nums)
if n == 0:
return 0
# 定义状态数组
# dp[i][0] 表示以 nums[i] 结尾的最长递增子序列的长度
# dp[i][1] 表示以 nums[i] 结尾的最长递增子序列的个数
dp = [[1, 1] for _ in range(n)]
max_length = 1 # 最长递增子序列的长度
for i in range(1, n):
for j in range(i):
if nums[j] < nums[i]:
if dp[j][0] + 1 > dp[i][0]: # 如果长度更长,则更新
dp[i][0] = dp[j][0] + 1
dp[i][1] = dp[j][1]
elif dp[j][0] + 1 == dp[i][0]: # 如果长度相等,则累加个数
dp[i][1] += dp[j][1]
max_length = max(max_length, dp[i][0]) # 更新最长递增子序列长度
res = 0
for i in range(n):
if dp[i][0] == max_length: # 如果长度等于最长递增子序列长度,则累加个数
res += dp[i][1]
return res
71. 简化路径
class Solution:
def simplifyPath(self, path: str) -> str:
stack = []
path = path.split("/")
for item in path:
if item == "..":
if stack : stack.pop()
elif item and item != ".":
stack.append(item)
return "/" + "/".join(stack)
442. 数组中重复的数据
class Solution:
def findDuplicates(self, nums: List[int]) -> List[int]:
for i in range(len(nums)):
while nums[i] != nums[nums[i]-1]:
nums[nums[i]-1], nums[i] = nums[i], nums[nums[i]-1]
return [num for i, num in enumerate(nums) if num-1 != i]
# 时间复杂度:O(n)
# 空间复杂度:O(1)
509. 斐波那契数
class Solution:
def fib(self, n: int) -> int:
p = 0; q = 1
for i in range(n):
p, q = q, p+q
return p % 1000000007
1047. 删除字符串中的所有相邻重复项
class Solution:
def removeDuplicates(self, s: str) -> str:
stk = list()
for ch in s:
if stk and stk[-1] == ch:
stk.pop()
else:
stk.append(ch)
return "".join(stk)
剑指 Offer 45. 把数组排成最小的数
class Solution:
def minNumber(self, nums: List[int]) -> str:
nums = sorted(map(str, nums), key=cmp_to_key(lambda x, y: int(x+y) - int(y+x)))
return '0' if nums[0] == 0 else ''.join(nums)
37. 解数独
class Solution:
def solveSudoku(self, board: List[List[str]]) -> None:
"""
Do not return anything, modify board in-place instead.
"""
self.backtracking(board)
def backtracking(self, board: List[List[str]]) -> bool:
# 若有解,返回True;若无解,返回False
for i in range(len(board)): # 遍历行
for j in range(len(board[0])): # 遍历列
# 若空格内已有数字,跳过
if board[i][j] != '.': continue
for k in range(1, 10):
if self.is_valid(i, j, k, board):
board[i][j] = str(k)
if self.backtracking(board): return True
board[i][j] = '.'
# 若数字1-9都不能成功填入空格,返回False无解
return False
return True # 有解
def is_valid(self, row: int, col: int, val: int, board: List[List[str]]) -> bool:
# 判断同一行是否冲突
for i in range(9):
if board[row][i] == str(val):
return False
# 判断同一列是否冲突
for j in range(9):
if board[j][col] == str(val):
return False
# 判断同一九宫格是否有冲突
start_row = (row // 3) * 3
start_col = (col // 3) * 3
for i in range(start_row, start_row + 3):
for j in range(start_col, start_col + 3):
if board[i][j] == str(val):
return False
return True
459. 重复的子字符串
class Solution:
def repeatedSubstringPattern(self, s: str) -> bool:
def kmp(pattern: str) -> bool:
n = len(pattern)
fail = [-1] * n
for i in range(1, n):
j = fail[i - 1]
while j != -1 and pattern[j + 1] != pattern[i]:
j = fail[j]
if pattern[j + 1] == pattern[i]:
fail[i] = j + 1
return fail[n - 1] != -1 and n % (n - fail[n - 1] - 1) == 0
return kmp(s)
剑指 Offer 34. 二叉树中和为某一值的路径
# 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 pathSum(self, root: TreeNode, targetSum: int) -> List[List[int]]:
res = list(); path = list()
def dfs(root: TreeNode, targetSum: int):
if not root: return
path.append(root.val)
targetSum -= root.val
if not root.left and not root.right and targetSum == 0:
res.append(path[:])
dfs(root.left, targetSum)
dfs(root.right, targetSum)
path.pop()
dfs(root, targetSum)
return res
剑指 Offer 53 - I. 在排序数组中查找数字 I
class Solution:
def search(self, nums: List[int], target: int) -> int:
def helper(t):
l = 0; r = len(nums)
while l < r:
m = (l + r) // 2
if nums[m] <= t: l = m + 1
else: r = m
# 模板2.3寻找右侧边界本来是返回 l-1, 这里返回 l 起始是目标值大一个数的左侧边界
return l
return helper(target) - helper(target - 1)
# 先找到第一个比target大的数的位置。
# 再找到第一个比target-1大的数的位置。
# 两个位置之差为结果
# 时间复杂度: O(logn) ,其中 n 为数组的长度。二分查找的时间复杂度为 O(logn),一共会执行两次,因此总时间复杂度为 O(logn)。
# 空间复杂度:O(1) 。只需要常数空间存放若干变量。
86. 分隔链表
# 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]:
l0 = l = ListNode(0); r0 = r = ListNode(0)
p = head
while p:
if p.val < x:
l.next = p
l = l.next
else:
r.next = p
r = r.next
p = p.next
l.next = r0.next
r.next = None
return l0.next
# 时间复杂度: O(n)
# 空间复杂度: O(1)
395. 至少有 K 个重复字符的最长子串
class Solution:
def longestSubstring(self, s: str, k: int) -> int:
if len(s) < k: return 0
for c in set(s):
if s.count(c) < k:
return max(self.longestSubstring(t, k) for t in s.split(c))
return len(s)
# 时间复杂度:O(N∗26∗26)
# 空间复杂度:O(26∗26)
210. 课程表 II
class Solution:
def findOrder(self, numCourses: int, prerequisites: List[List[int]]) -> List[int]:
# 存储有向图
edges = collections.defaultdict(list)
# 标记每个节点的状态:0=未搜索,1=搜索中,2=已完成
visited = [0] * numCourses
# 用数组来模拟栈,下标 0 为栈底,n-1 为栈顶
result = list()
# 判断有向图中是否有环
valid = True
for info in prerequisites:
edges[info[1]].append(info[0])
def dfs(u: int):
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 list()
# 如果没有环,那么就有拓扑排序
# 注意下标 0 为栈底,因此需要将数组反序输出
return result[::-1]