目录
1. 栈。删除最外层括号
- 题目描述:有效括号字符串为空 ("")、"(" + A + ")" 或 A + B,其中 A 和 B 都是有效的括号字符串,+ 代表字符串的连接。例如,"","()","(())()" 和 "(()(()))" 都是有效的括号字符串。如果有效字符串 S 非空,且不存在将其拆分为 S = A+B 的方法,我们称其为原语(primitive),其中 A 和 B 都是非空有效括号字符串。给出一个非空有效字符串 S,考虑将其进行原语化分解,使得:S = P_1 + P_2 + ... + P_k,其中 P_i 是有效括号字符串原语。对 S 进行原语化分解,删除分解中每个原语字符串的最外层括号,返回 S 。
输入:"(()())(())" 输出:"()()()" 解释:输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())",删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。
- 解法。找到原语(左括号等于右括号数),然后对原语剥掉最外层。用2个栈,res是存储截至目前的结果,st是辅助栈存储当前原语的结果。变量balanced记录当前左右括号数是否平衡,通过balanced是否为0判断当前是处于首尾还是中间,若是非首尾就要放到st里,然后一旦原语遍历结束了就把st的内容取出来再清空
-
class Solution: def removeOuterParentheses(self, S: str) -> str: if not S: return "" st = [] i = 0 balanced = 0 res = [] while i < len(S): if S[i] == '(': if balanced != 0: st.append(S[i]) balanced += 1 elif S[i] == ')': balanced -= 1 if balanced != 0: st.append(S[i]) else: res += st st = [] i += 1 return ''.join(res)
2. 树。从根到叶的二进制数之和
- 题目描述:给出一棵二叉树,其上每个结点的值都是 0 或 1 。每一条从根到叶的路径都代表一个从最高有效位开始的二进制数。例如,如果路径为 0 -> 1 -> 1 -> 0 -> 1,那么它表示二进制数 01101,也就是 13 。对树上的每一片叶子,我们都要找出从根到该叶子的路径所表示的数字。以 10^9 + 7 为模,返回这些数字之和。
输入:[1,0,1,0,1,0,1] 输出:22 解释:(100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
- 解法。DFS的方式存储下从根节点到叶子结点的二进制数对应的十进制值,注意可以一边递归一边计算
-
class Solution: def sumRootToLeaf(self, root: TreeNode) -> int: if not root: return 0 res = [] self.helper(root, 0, res) return sum(res) if sum(res) < 2**31 else 2**31-1 def helper(self, root, cur, res): if not root: return if not root.left and not root.right: res.append(cur*2+root.val) return self.helper(root.left, cur*2+root.val, res) self.helper(root.right, cur*2+root.val, res) return
3. 字符串。驼峰式匹配
- 题目描述:如果我们可以将小写字母插入模式串 pattern 得到待查询项 query,那么待查询项与给定模式串匹配。(我们可以在任何位置插入每个字符,也可以插入 0 个字符。)给定待查询列表 queries,和模式串 pattern,返回由布尔值组成的答案列表 answer。只有在待查项 queries[i] 与模式串 pattern 匹配时, answer[i] 才为 true,否则为 false。
输出:queries = ["FooBar","FooBarTest","FootBall","FrameBuffer","ForceFeedBack"], pattern = "FoBaT"
输入:[false,true,false,false,false]
解释: "FooBarTest" 可以这样生成:"Fo" + "o" + "Ba" + "r" + "T" + "est".
- 解法。对于被匹配的queries,匹配两者相等的字母,剩余的跳过即可。匹配完毕可能是queries先匹配完,也可能是pattern先匹配完,分清楚情况
class Solution:
def camelMatch(self, queries: List[str], pattern: str) -> List[bool]:
if not queries or not pattern:
return []
res = []
for q in queries:
if self.match(q, pattern):
res.append(True)
else:
res.append(False)
return res
def match(self, que, patt):
if not que:
return False
i, j = 0, 0
while i < len(que) and j < len(patt):
if que[i] == patt[j]:
i += 1
j += 1
continue
else:
if 'A' <= que[i] <= 'Z':
return False
i += 1
while i < len(que):
if 'A' <= que[i] <= 'Z':
return False
i += 1
if j == len(patt):
return True
else:
return False
4. DP。视频拼接
- 题目描述:你将会获得一系列视频片段,这些片段来自于一项持续时长为 T 秒的体育赛事。这些片段可能有所重叠,也可能长度不一。视频片段 clips[i] 都用区间进行表示:开始于 clips[i][0] 并于 clips[i][1] 结束。我们甚至可以对这些片段自由地再剪辑,例如片段 [0, 7] 可以剪切成 [0, 1] + [1, 3] + [3, 7] 三部分。我们需要将这些片段进行再剪辑,并将剪辑后的内容拼接成覆盖整个运动过程的片段([0, T])。返回所需片段的最小数目,如果无法完成该任务,则返回 -1 。
输入:clips = [[0,1],[6,8],[0,2],[5,6],[0,4],[0,3],[6,7],[1,3],[4,7],[1,4],[2,5],[2,6],[3,4],[4,5],[5,7],[6,9]], T = 9 输出:3 解释: 我们选取片段 [0,4], [4,7] 和 [6,9] 。
- 解法。
- 解法1,可以从图搜的角度理解,确定好起点,然后遍历找最短路径
- 解法2,贪心的角度,这里贪心的思想不是体现在每次吞并能吞并的(只要能拓展范围),而是把能辐射到的范围看为1个组里的(就是内层while循环遍历过的都属于一个组),最终res记录的其实就是有几个组,并且每次取的都是组内的最优范围
-
# 解法1 class Solution: def videoStitching(self, clips: List[List[int]], T: int) -> int: if not clips: return -1 n = len(clips) # 必须要这么排才能找到最短路径 clips.sort(key = lambda x: (x[0], -x[1])) if clips[0][0] > 0: return -1 visited = [False for _ in range(n)] visited[0] = True q = [(clips[0], 1)] while q: cur, level = q.pop(0) if cur[0] <= 0 and cur[1] >= T: return level # 因为取了clips[0]作为起点,所以此处就从1开始 for i in range(1, len(clips)): if not visited[i]: if clips[i][0] >= cur[0] and clips[i][1] <= cur[1]: visited[i] = True continue elif clips[i][0] <= cur[1]: visited[i] = True # 此处的剪枝可以略去,无妨 # if q and max(cur[1], clips[i][1]) >= q[0][0][1]: # q.pop(0) q.append(([min(cur[0], clips[i][0]), max(cur[1], clips[i][1])], level+1)) return -1
-
# 解法2 class Solution: def videoStitching(self, clips: List[List[int]], T: int) -> int: if not clips or T <= 0: return 0 # 这里排序可以是双升序,也可以是x[0]升序x[1]降序 clips.sort() res = 0 cur_end, max_end = 0, 0 i = 0 n = len(clips) while i < n: if clips[i][0] > cur_end: return -1 max_end = cur_end while i < n and clips[i][0] <= cur_end: if clips[i][1] > max_end: max_end = clips[i][1] i += 1 res += 1 cur_end = max_end if cur_end >= T: return res return -1