LeetCode Weekly Contest 131题解
5016. 删除最外层的括号
有效括号字符串为空
("")
、"(" + A + ")"
或A + B
,其中A
和B
都是有效的括号字符串,+
代表字符串的连接。例如,""
,"()"
,"(())()"
和"(()(()))"
都是有效的括号字符串。如果有效字符串
S
非空,且不存在将其拆分为S = A+B
的方法,我们称其为原语(primitive),其中A
和B
都是非空有效括号字符串。给出一个非空有效字符串
S
,考虑将其进行原语化分解,使得:S = P_1 + P_2 + ... + P_k
,其中P_i
是有效括号字符串原语。对
S
进行原语化分解,删除分解中每个原语字符串的最外层括号,返回S
。
示例 1:
输入:"(()())(())" 输出:"()()()" 解释: 输入字符串为 "(()())(())",原语化分解得到 "(()())" + "(())", 删除每个部分中的最外层括号后得到 "()()" + "()" = "()()()"。
示例 2:
输入:"(()())(())(()(()))" 输出:"()()()()(())" 解释: 输入字符串为 "(()())(())(()(()))",原语化分解得到 "(()())" + "(())" + "(()(()))", 删除每隔部分中的最外层括号后得到 "()()" + "()" + "()(())" = "()()()()(())"。
示例 3:
输入:"()()" 输出:"" 解释: 输入字符串为 "()()",原语化分解得到 "()" + "()", 删除每个部分中的最外层括号后得到 "" + "" = ""。
提示:
S.length <= 10000
S[i]
为"("
或")"
S
是一个有效括号字符串思路:
- 栈
- 创建一个结果串res,若栈中没有元素,且是左括号,直接入栈
- 若栈中有元素,若是左括号,入栈并且将左括号拼接到res中,若是右括号,则从栈顶弹出一个左括号,若弹出的左括号不是栈中最后一个元素就将右括号拼接到res中
AcCode:
class Solution { public String removeOuterParentheses(String S) { StringBuilder builder = new StringBuilder(); Stack<Character> stack = new Stack<Character>(); for (int i = 0; i < S.length(); i++) { if(stack.isEmpty()) { if((S.charAt(i)=='(')) { stack.push(Character.valueOf('(')); } }else { if((S.charAt(i)==')')) { char temp = stack.pop(); if(stack.isEmpty()) { continue; } }else if((S.charAt(i)=='(')) { stack.push(Character.valueOf('(')); } builder.append(S.charAt(i)); } } return builder.toString(); } }
5017. 从根到叶的二进制数之和
给出一棵二叉树,其上每个结点的值都是
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
提示:
- 树中的结点数介于
1
和1000
之间。- node.val 为
0
或1
。思路:
- 先序遍历+递推
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public long res = 0; public int sumRootToLeaf(TreeNode root) { firstSearch(root, 0); return (int)res; } private static final int MOD = 1000000007; public void firstSearch(TreeNode root,long sum) { if(root==null) { return; } sum = (2*sum+root.val)%MOD; //res = (res+sum)%(1000000007); if(root.left==null && root.right==null) { res = (res+sum)%MOD; return; } firstSearch(root.left, sum); firstSearch(root.right, sum); } }
5018. 驼峰式匹配
如果我们可以将小写字母插入模式串
pattern
得到待查询项query
,那么待查询项与给定模式串匹配。(我们可以在任何位置插入每个字符,也可以插入 0 个字符。)给定待查询列表
queries
,和模式串pattern
,返回由布尔值组成的答案列表answer
。只有在待查项queries[i]
与模式串pattern
匹配时,answer[i]
才为true
,否则为false
。
示例 1:
输入:queries = ["FooBar","FooBarTest","FootBall","FrameBuffer","ForceFeedBack"], pattern = "FB" 输出:[true,false,true,true,false] 示例: "FooBar" 可以这样生成:"F" + "oo" + "B" + "ar"。 "FootBall" 可以这样生成:"F" + "oot" + "B" + "all". "FrameBuffer" 可以这样生成:"F" + "rame" + "B" + "uffer".
示例 2:
输入:queries = ["FooBar","FooBarTest","FootBall","FrameBuffer","ForceFeedBack"], pattern = "FoBa" 输出:[true,false,true,false,false] 解释: "FooBar" 可以这样生成:"Fo" + "o" + "Ba" + "r". "FootBall" 可以这样生成:"Fo" + "ot" + "Ba" + "ll".
示例 3:
输出:queries = ["FooBar","FooBarTest","FootBall","FrameBuffer","ForceFeedBack"], pattern = "FoBaT" 输入:[false,true,false,false,false] 解释: "FooBarTest" 可以这样生成:"Fo" + "o" + "Ba" + "r" + "T" + "est".
提示:
1 <= queries.length <= 100
1 <= queries[i].length <= 100
1 <= pattern.length <= 100
- 所有字符串都仅由大写和小写英文字母组成。
思路:
- 暴力
- 先遍历一遍模式串pattern,使用集合list记录一下所有大写字母和其对应的下标
- 对于待查询串s是否可以由模式串生成可以采用如下做法:
- 跟前面一样遍历一遍待查询串s,使用集合tempList记录一下所有大写字母和其对应的下标
- 之后先判断一下list.size()是否与tempList.size()相等,若不相等返回false,否则我们还需要继续判断
- 遍历list和tempList,查看是否大写字母的顺序是否相同,若不相同返回false,否则我们还需要继续判断
- 再次遍历list和tempList,查看待查询串两个相邻大写字母之间是否按顺序包含模式串对应的两个大写字母之间的小写字母,若包含返回true,不包含返回false
- 这方法是比较麻烦的...如果有更好的思路,欢迎留言指点
AcCode:
class Solution { private static class BigWord implements Comparable<BigWord>{ Character bigWord = null; int index; public BigWord(Character bigword,int index) { this.bigWord = bigword; this.index = index; } @Override public int compareTo(BigWord o) { return bigWord.compareTo(o.bigWord); } } public List<Boolean> camelMatch(String[] queries, String pattern) { List<BigWord> list = new ArrayList<Solution.BigWord>(); for (int i = 0; i < pattern.length(); i++) { if('A'<=pattern.charAt(i) && pattern.charAt(i)<='Z') { list.add(new BigWord(pattern.charAt(i), i)); } } List<Boolean> resList = new ArrayList<Boolean>(); OUT: for (int i = 0; i < queries.length; i++) { String word = queries[i]; List<BigWord> tempList = new ArrayList<Solution.BigWord>(); for (int j = 0; j < word.length(); j++) { if('A'<=word.charAt(j) && word.charAt(j)<='Z') { tempList.add(new BigWord(word.charAt(j), j)); } } if(tempList.size()!=list.size()) { resList.add(false); continue OUT; }else { for (int j = 0; j < tempList.size(); j++) { if(tempList.get(j).compareTo(list.get(j))!=0) { resList.add(false); continue OUT; } } for (int j = 0; j < tempList.size()-1; j++) { String tempChar = pattern.substring(list.get(j).index+1, list.get(j+1).index); if(list.get(j).index+1>=list.get(j+1).index) { continue; } int index = 0; for (int k = tempList.get(j).index+1; k < word.length() && k<tempList.get(j+1).index; k++) { if(word.charAt(k)==tempChar.charAt(index)) { index++; } if(index==tempChar.length()) { break; } } if(index<tempChar.length()) { resList.add(false); continue OUT; } } if(tempList.size()-1>=0) { String tempChar = pattern.substring(list.get(tempList.size()-1).index+1); if(list.get(tempList.size()-1).index+1>=pattern.length()) { resList.add(true); continue OUT; } int index = 0; for (int k = tempList.get(tempList.size()-1).index+1; k < word.length(); k++) { if(word.charAt(k)==tempChar.charAt(index)) { index++; } if(index==tempChar.length()) { break; } } if(index<tempChar.length()) { resList.add(false); continue OUT; } resList.add(true); }else { resList.add(true); } } } return resList; } }
5019. 视频拼接
你将会获得一系列视频片段,这些片段来自于一项持续时长为
T
秒的体育赛事。这些片段可能有所重叠,也可能长度不一。视频片段
clips[i]
都用区间进行表示:开始于clips[i][0]
并于clips[i][1]
结束。我们甚至可以对这些片段*地再剪辑,例如片段[0, 7]
可以剪切成[0, 1] + [1, 3] + [3, 7]
三部分。我们需要将这些片段进行再剪辑,并将剪辑后的内容拼接成覆盖整个运动过程的片段(
[0, T]
)。返回所需片段的最小数目,如果无法完成该任务,则返回-1
。
示例 1:
输入:clips = [[0,2],[4,6],[8,10],[1,9],[1,5],[5,9]], T = 10 输出:3 解释: 我们选中 [0,2], [8,10], [1,9] 这三个片段。 然后,按下面的方案重制比赛片段: 将 [1,9] 再剪辑为 [1,2] + [2,8] + [8,9] 。 现在我们手上有 [0,2] + [2,8] + [8,10],而这些涵盖了整场比赛 [0, 10]。
示例 2:
输入:clips = [[0,1],[1,2]], T = 5 输出:-1 解释: 我们无法只用 [0,1] 和 [0,2] 覆盖 [0,5] 的整个过程。
示例 3:
输入: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] 。
示例 4:
输入:clips = [[0,4],[2,8]], T = 5 输出:2 解释: 注意,你可能录制超过比赛结束时间的视频。
提示:
1 <= clips.length <= 100
0 <= clips[i][0], clips[i][1] <= 100
0 <= T <= 100
思路:
- 经典贪心问题(区间覆盖)
- 题目要求就是要在若干的区间[beginIndex,endIndex]选择最小的区间构成[0,T]的目标区间
- 先进行筛选,若一个区间的endIndex<0 或者 beginIndex>T 是不可能构成目标区间的,这些区间直接不要
- 将筛完后剩下的区间进行按beginIndex进行排序
- 这里定义两个变量,b=0和e=-1
- 若区间beginIndex>b那么是不可能构成目标区间的,直接返回-1
- 若区间beginIndex<=b,需要在所有beginInex<=b的区间找到最大的endIndex,记为maxIndex
- 找到最大的endIndex之后,将maxIndex作为beginIndex如此循环直至maxIndex>=T
AcCode:
import java.util.ArrayList; import java.util.Collections; import java.util.List; class Solution { private static class Qj implements Comparable<Qj>{ int beginIndex; int endIndex; public Qj(int beginIndex,int endIndex) { this.beginIndex = beginIndex; this.endIndex = endIndex; } @Override public int compareTo(Qj o) { int res = beginIndex-o.beginIndex; if(res==0) { return endIndex-o.endIndex; }else { return res; } } @Override public String toString() { // TODO Auto-generated method stub return beginIndex+" "+endIndex; } } public int videoStitching(int[][] clips, int T) { List<Qj> qjs = new ArrayList<Solution.Qj>(); for (int i = 0; i < clips.length; i++) { if(clips[i][0]<=T) { qjs.add(new Qj(clips[i][0], clips[i][1])); } } Collections.sort(qjs); int beginIndex = 0; int maxIndex = -1; int count = 0; for (int i = 0; i < qjs.size(); i++) { if(qjs.get(i).beginIndex>beginIndex) { if(qjs.get(i).beginIndex<=maxIndex) { //更新 beginIndex = maxIndex; count++; i--; }else { return -1; } }else { if(qjs.get(i).endIndex>maxIndex) { maxIndex = qjs.get(i).endIndex; if(maxIndex>=T) { count++; break; } } } } if(maxIndex<T) { return -1; } return count; } }