1.题目基本信息
1.1.题目描述
给定一个表示代码片段的字符串,你需要实现一个验证器来解析这段代码,并返回它是否合法。合法的代码片段需要遵守以下的所有规则:
-
代码必须被合法的闭合标签包围。否则,代码是无效的。
-
闭合标签(不一定合法)要严格符合格式:
TAG_CONTENT 。其中,是起始标签, 是结束标签。起始和结束标签中的 TAG_NAME 应当相同。当且仅当 TAG_NAME 和 TAG_CONTENT 都是合法的,闭合标签才是合法的。 -
合法的 TAG_NAME 仅含有大写字母,长度在范围 [1,9] 之间。否则,该 TAG_NAME 是不合法的。
-
合法的 TAG_CONTENT 可以包含其他合法的闭合标签,cdata (请参考规则7)和任意字符(注意参考规则1)除了不匹配的<、不匹配的起始和结束标签、不匹配的或带有不合法 TAG_NAME 的闭合标签。否则,TAG_CONTENT 是不合法的。
-
一个起始标签,如果没有具有相同 TAG_NAME 的结束标签与之匹配,是不合法的。反之亦然。不过,你也需要考虑标签嵌套的问题。
-
一个<,如果你找不到一个后续的>与之匹配,是不合法的。并且当你找到一个<或的前的字符,都应当被解析为 TAG_NAME(不一定合法)。
-
cdata 有如下格式:<![CDATA[CDATA_CONTENT]]>。CDATA_CONTENT 的范围被定义成 <![CDATA[ 和后续的第一个 ]]>之间的字符。
-
CDATA_CONTENT 可以包含任意字符。cdata 的功能是阻止验证器解析CDATA_CONTENT,所以即使其中有一些字符可以被解析为标签(无论合法还是不合法),也应该将它们视为常规字符。
1.2.题目地址
https://leetcode.cn/problems/tag-validator/description/
2.解题方法
2.1.解题思路
栈+一次遍历
2.2.解题步骤
第一步,构建维护变量。tagsStack栈维护已经遍历到且没有闭合的
第二步,遍历,并进行分类讨论
-
2.1.分为、<!xxx>、
三种情况进行分类讨论 -
2.2.非<的字符情况讨论
第三步,如果所有标签都闭合,即栈为空,说明代码段合法
3.解题代码
python代码
class Solution:
def isValid(self, code: str) -> bool:
# 思路:栈+一次遍历
n = len(code)
# 第一步,构建维护变量。tagsStack栈维护已经遍历到且没有闭合的<tagname>的标签名
tagsStack = []
i = 0
# 第二步,遍历,并进行分类讨论
while i < n:
if code[i] == "<":
# 2.1.分为</tagname>、<!xxx>、<tagname>三种情况进行分类讨论
if i == n - 1:
return False
if code[i + 1] == "/":
if not tagsStack:
return False
j = i + 2
while j < n and code[j] != ">":
j += 1
if j == n:
return False
tagname = code[i + 2:j]
if tagname != tagsStack[-1]:
return False
tagsStack.pop()
i = j + 1
if i != n and len(tagsStack) == 0:
# 多个匹配标签的情况,如<A></A><B></B>
return False
elif code[i + 1] == "!":
if not tagsStack:
return False
j = i + 9
if code[i + 2:j] != "[CDATA[":
return False
while j < n and code[j:j + 3] != "]]>":
j += 1
if j == n:
return False
i = j + 3
else:
j = i + 1
while j < n and code[j] != ">":
j += 1
if j == n:
return False
tagname = code[i + 1:j]
if not (1 <= len(tagname) <= 9 and all(ord('A') <= ord(ch) <= ord('Z') for ch in tagname)):
return False
tagsStack.append(tagname)
i = j + 1
else:
# 2.2.非<的字符情况讨论
if len(tagsStack) == 0:
return False
i += 1
# 第三步,如果所有标签都闭合,即栈为空,说明代码段合法
return len(tagsStack) == 0
c++代码
class Solution {
public:
bool isValid(string code) {
int n = code.size();
stack<string> tagsStack;
int i = 0;
while (i < n) {
if (code[i] == '<') {
if (i == n - 1) {
return false;
}
if (code[i + 1] == '/') {
if (tagsStack.empty()) {
return false;
}
int j = i + 2;
while (j < n && code[j] != '>') {
j++;
}
if (j == n) {
return false;
}
string tagname = code.substr(i + 2, j - i - 2);
if (tagname != tagsStack.top()) {
return false;
}
tagsStack.pop();
i = j + 1;
if (tagsStack.empty() && i != n) {
return false;
}
} else if (code[i + 1] == '!') {
if (tagsStack.empty()) {
return false;
}
int j = i + 9;
if (code.substr(i + 2, 7) != "[CDATA[") {
return false;
}
while (j < n && code.substr(j, 3) != "]]>") {
j++;
}
if (j == n) {
return false;
}
i = j + 3;
} else {
int j = i + 1;
while (j < n && code[j] != '>') {
j++;
}
if (j == n) {
return false;
}
string tagname = code.substr(i + 1, j - i - 1);
bool flag1 = true; // 是否全部为大写字符
for (char ch: tagname) {
if (ch < 'A' || ch > 'Z') {
flag1 = false;
break;
}
}
if (!flag1 || tagname.size() < 1 || tagname.size() > 9) {
return false;
}
tagsStack.push(tagname);
i = j + 1;
}
} else {
if (tagsStack.empty()) {
return false;
}
i++;
}
}
return tagsStack.empty();
}
};
4.执行结果










