0%

591.标签验证器

题目

标签验证器

思路

如果当前字符为 <,需要考虑下面四种情况:

  • 如果下一个字符为 /,那么说明我们遇到了一个结束标签。我们需要定位下一个 > 的位置 j,此时 code[i+2..j−1] 就是该结束标签的名称。我们需要判断该名称与当前栈顶的名称是否匹配,如果匹配,说明名称的标签已经闭合,我们需要将当前栈顶的名称弹出。同时根据规则 1,我们需要保证整个 code 被闭合标签包围,因此如果栈中已经没有标签,但是 j 并不是 code 的末尾,那么说明后续还会有字符,它们不被闭合标签包围。
  • 如果下一个字符为 !,那么说明我们遇到了一个 cdata,我们需要继续往后读 77 个字符,判断其是否为 \texttt{[CDATA[}[CDATA[。在这之后,我们定位下一个 ]]> 的位置 j,此时 code[i+9..j−1] 就是 cdata 中的内容,它不需要被解析,所以我们也不必进行任何验证。需要注意的是,根据规则 1,栈中需要存在至少一个开放的标签。
  • 如果下一个字符为大写字母,那么说明我们遇到了一个开始标签。我们需要定位下一个 > 的位置 j,此时 code[i+2..j−1] 就是该开始标签的名称。我们需要判断该名称是否恰好由 1 至 9 个大写字母组成,如果是,说明该标签合法,我们需要将该名称放入栈顶。
  • 除此之外,如果不存在下一个字符,或者下一个字符不属于上述三种情况,那么 code 是不合法的。

如果当前的字符为其它字符,那么根据规则 1,栈中需要存在至少一个开放的标签。

在遍历完成后,我们还需要保证此时栈中没有任何(还没有结束的)标签。

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
class Solution {
public:
bool isValid(string code) {
stack<string> stk;
int i = 0, n = code.size();
while(i < n){
if(code[i] == '<'){ // 当前字符为 <
if(i == n - 1) return false;
else if(code[i + 1] >= 'A' && code[i + 1] <= 'Z'){ // 下一个字符是大写字母
int j = code.find('>', i); // 从i开始找,找到第一个 >,并返回其下标
if(j == string::npos) return false; // 不存在 >
string str = code.substr(i + 1, j - i - 1);
if(str.length() < 1 || str.length() > 9) return false; // 判断长度是否合法
for(int k = 0; k < str.size(); k ++){ // 判断是否全为大写字母
if(str[k] < 'A' || str[k] > 'Z')
return false;
}
stk.push(str);
i = j + 1;
}
else if(code[i + 1] == '/'){
int j = code.find('>', i);
if(j == string::npos) return false;
string str = code.substr(i + 2, j - i - 2);
if(stk.empty() || stk.top() != str) return false; // 如果栈顶元素为空 或者 和栈顶元素不匹配
stk.pop();
i = j + 1;
if(stk.empty() && i != n) return false; // 如果栈为空,但是还没遍历到字符串末尾
}
else if(code[i + 1] == '!'){
if(stk.empty()) return false;
string str = code.substr(i + 2, 7); // 往后读7个字符
if(str != "[CDATA[") return false;
int j = code.find("]]>", i);
if(j == string::npos) return false;
i = j + 1;
}
else return false;
}
else{
if(stk.empty()) return false; // 当前字符为其他字符,但是栈为空了,
i++;
}
}
return stk.empty(); // 可能还存在栈最后还不空的情况
}
};
  • 时间复杂度:O(n),其中 ncode 的长度,我们只需要对 code 进行一次遍历。
  • 空间复杂度:O(n),即为栈存储标签名称需要使用的空间。

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户

内存消耗:6.3 MB, 在所有 C++ 提交中击败了96.00%的用户

通过测试用例:260 / 260

正在加载今日诗词....