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
是一个有效括号字符串
class Solution {
public:
string removeOuterParentheses(string S) {
string ans = "", cur = "";
stack<char> CS;
for(int i = 0; i < S.length(); i++) {
if(CS.size() <= 1) {
if(S[i] == ')') {
CS.pop();
continue;
}
if(CS.size()) cur += "("; //栈中存有最外层左括号,故s[i]是原语第一个字符
CS.push('(');
}
else {
if(S[i] == ')') {
CS.pop();
cur += ")";
ans += cur;
cur = "";
}
else {
CS.push('(');
cur += "(";
}
}
}
return ans;
}
};
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.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
int ans = 0;
public:
/*
dfs
T: O(n), S: O(h)(h为树的深度)
*/
int sumRootToLeaf(TreeNode* root) {
dfs(root, 0, 1e9 + 7);
return ans;
}
void dfs(TreeNode* root, int cur, const int P) {
if(!root) return; //
cur = (cur*2 + root->val) % P;
if(root->left == NULL && root->right == NULL) {
ans = (ans + cur) % P;
return;
}
dfs(root->left, cur, P);
dfs(root->right, cur, P);
}
};
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
- 所有字符串都仅由大写和小写英文字母组成。
class Solution {
public:
//匹配时注意顺序且pattern能在插入小写字符后与query完全匹配
vector<bool> camelMatch(vector<string>& queries, string pattern) {
vector<bool> f(queries.size(), true);
for(int i = 0; i < queries.size(); i++) {
bool find = true;
int k = 0, j = 0;
while(k < pattern.length() && j < queries[i].length()) {
if(queries[i][j] == pattern[k]) {
k++;
j++;
}
//不匹配:如果是小写字符,可以在pattern[k]前插入queries[i][j],否则插入字符也无法完成匹配
else {
if(queries[i][j] >= 'a' && queries[i][j] <= 'z') j++;
else break;
}
}
if(k < pattern.length()) find = false; //
while(j < queries[i].length()) {
if(queries[i][j] >= 'A' && queries[i][j] <= 'Z') { //query多出pattern(已插入部分小写字符)部分中有大写字符
find = false;
break;
}
j++;
}
f[i] = find;
}
return f;
}
};
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
class Solution {
public:
/*
-------------------------------------------贪心------------------------------------
首先对clips进行排序(先对starting time升序,然后对ending time升序(分别记为st和et)),
一开始选择st1=0而interval最长的clip[st1, et1],接下来选择[st2, et2],使st2<=et1且et2-et1最大,
继续这种选择直到eti>=T或者clips已经选择完
*/
int videoStitching(vector<vector<int>>& clips, int T) {
int cnt = 0;
vector<vector<int>> _clips = clips;
sort(_clips.begin(), _clips.end(), cmp);
int i = 0;
int st = _clips[i][0], et = _clips[i][1];
if(st) cnt = -1;
else {
while(++i < _clips.size() && !_clips[i][0]) et = _clips[i][1]; //st为0的clip要特殊处理
cnt++;
if(et < T) { //否则后面可能会多增加一次clip合并
int curDeltaMax = 0;
int newET = et;
for(; i < _clips.size(); i++) {
if(_clips[i][0] <= et) {
if(_clips[i][1]-et > curDeltaMax) { //更新下一个et
curDeltaMax = _clips[i][1]-et;
newET = _clips[i][1];
}
continue;
}
if(newET == et) break; //区间中断
else {
cnt++; //add 1
et = newET; //
if(et >= T) break; //
curDeltaMax = 0;
i--;
}
}
if(newET < T) cnt = -1;
else {
if(et != newET) cnt++; //newET进行了更新但未及时赋值给et
}
}
}
return cnt;
}
static bool cmp(const vector<int>& clip1, const vector<int>& clip2) { //add static
if(clip1[0] < clip2[0]) return true;
else if(clip1[0] == clip2[0]) {
if(clip1[1] < clip2[1]) return true;
else return false;
}
else return false;
}
};