652. 寻找重复的子树【DFS+哈希+序列化】
思路
将二叉树的每棵树都序列化(深度优先遍历),再用哈希表存储,判断是否有两次,有就是重复子树
AC代码
class Solution:
def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]:
def dfs(node: Optional[TreeNode]) -> str:
if not node:
return ""
serial = "".join(str(node.val) + "(" + dfs(node.left) + ")(" + dfs(node.right) + ")")
if tree:=tmp.get(serial, None):
ans.add(tree)
else:
tmp[serial] = node
return serial
tmp = dict()
ans = set()
dfs(root)
return list(ans)
828. 统计子串中的唯一字符【数学+ 思维】
思路
本题参考LeetCode上面一位大佬的思路。
AC代码
class Solution:
def uniqueLetterString(self, s: str) -> int:
n = len(s)
l = [0] * n # 记为字母ch上次出现的位置
r = [0] * n # 即为字母ch下次出现的位置
cnt = [-1] * 26
for i, ch in enumerate(s):
ch = ord(ch) - 65
l[i] = cnt[ch]
cnt[ch] = i
cnt = [n] * 26
for i in range(n - 1, -1, -1):
ch = ord(s[i]) - 65
r[i] = cnt[ch]
cnt[ch] = i
# 中间字符对(l, r)的字符串贡献(i - l) * (r - i)
ans = 0
for i in range(n):
ans += (i - l[i]) * (r[i] - i)
return ans
1592. 重新排列单词间的空格【模拟】
思路
将句子中的单词和空格数统计下来,再按照题目描述拼接。
AC代码
class Solution:
def reorderSpaces(self, text: str) -> str:
cnt_1 = text.count(' ')
tmp = text.split()
cnt_2 = len(tmp)
# 有坑
if cnt_2 == 1:
return tmp[0] + " "*cnt_1
n = cnt_1 // (cnt_2 - 1)
m = cnt_1 % (cnt_2 - 1)
ans = ""
for i, t in enumerate(tmp):
ans += t
if i != cnt_2 - 1:
ans += " "*n
ans += " "*m
return ans
667. 优美的排列 II【构造题】
思路
有三种情况
- 当 k = 1时,直接输出1 ,2,…, n
- 当 k = n - 1时, 1, n, 2, n - 1, 3, n - 2…1
- 当 1 < k < n - 1时,可以用前面两个结合,1, 2,…, n - k - 1, n - k, n, n - k - 1, n - 1…
AC代码
class Solution:
def constructArray(self, n: int, k: int) -> List[int]:
# 1, 2, ... n - k - 1, | n - k , n, n - k + 1, n - 1
ans = list(range(1, n - k))
i, j = n - k, n
while i <= j:
ans.append(i)
if i != j:
ans.append(j)
i += 1
j -= 1
return ans
1598. 文件夹操作日志搜集器【简单模拟】
思路
略
AC代码
class Solution:
def minOperations(self, logs: List[str]) -> int:
ans = 0
for log in logs:
if log[0] == '.' and log[1] == '.' and ans > 0:
ans -= 1
elif log[0] != '.':
ans += 1
return ans
669. 修剪二叉搜索树【二叉搜索树的删除】
思路
递归删除满足条件的数
AC代码
# 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 trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
# 二叉搜索树的删除
if not root:
return None
# 如果当前值小于[low, high],则满足的值可能在右子树,递归右子树
if root.val < low:
return self.trimBST(root.right, low, high)
# 如果当前值大于[low, high],则满足的值可能在左子树,递归左子树
if root.val > high:
return self.trimBST(root.left, low, high)
# 满足条件的值,将其删除
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
return root
857. 雇佣 K 名工人的最低成本【贪心+大根堆】
思路
这个题想到了贪心,但是没想到用大根堆来维护前k个元素。当堆里有k个工人时,如果quality比堆顶小,则将其压入堆中,因为quality小,则w小。
AC代码
class Solution:
def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float:
qw = sorted(zip(quality, wage), key=lambda p: p[1]/p[0]) # 对ri进行升序排序
h = [-q for q, _ in qw[:k]] # 利用"-"巧妙构造大根堆
heapify(h) # 将list转化为heap
sum_q = -sum(h)
ans = sum_q * qw[k - 1][1] / qw[k - 1][0] # 选ri最小的k名工人组成最优解
for q, w in qw[k:]:
if q < -h[0]: # 如果存在quality比堆顶的还小,就更新.
sum_q += heapreplace(h, -q) + q
ans = min(ans, sum_q * w / q)
return ans