Given a string representing a code snippet, implement a tag validator to parse the code and return whether it is valid.
A code snippet is valid if all the following rules hold:
<TAG_NAME>TAG_CONTENT</TAG_NAME>
. Among them, <TAG_NAME>
is the start tag, and </TAG_NAME>
is the end tag. The TAG_NAME in start and end tags should be the same. A closed tag is valid if and only if the TAG_NAME and TAG_CONTENT are valid.TAG_NAME
only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME
is invalid.TAG_CONTENT
may contain other valid closed tags, cdata and any characters (see note1) EXCEPT unmatched <
, unmatched start and end tag, and unmatched or closed tags with invalid TAG_NAME. Otherwise, the TAG_CONTENT
is invalid.<
is unmatched if you cannot find a subsequent >
. And when you find a <
or </
, all the subsequent characters until the next >
should be parsed as TAG_NAME (not necessarily valid).<![CDATA[CDATA_CONTENT]]>
. The range of CDATA_CONTENT
is defined as the characters between <![CDATA[
and the first subsequent ]]>
.CDATA_CONTENT
may contain any characters. The function of cdata is to forbid the validator to parse CDATA_CONTENT
, so even it has some characters that can be parsed as tag (no matter valid or invalid), you should treat it as regular characters.
Example 1:
Input: code = "<DIV>This is the first line <![CDATA[<div>]]></DIV>" Output: true Explanation: The code is wrapped in a closed tag : <DIV> and </DIV>. The TAG_NAME is valid, the TAG_CONTENT consists of some characters and cdata. Although CDATA_CONTENT has an unmatched start tag with invalid TAG_NAME, it should be considered as plain text, not parsed as a tag. So TAG_CONTENT is valid, and then the code is valid. Thus return true.
Example 2:
Input: code = "<DIV>>> ![cdata[]] <![CDATA[<div>]>]]>]]>>]</DIV>" Output: true Explanation: We first separate the code into : start_tag|tag_content|end_tag. start_tag -> "<DIV>" end_tag -> "</DIV>" tag_content could also be separated into : text1|cdata|text2. text1 -> ">> ![cdata[]] " cdata -> "<![CDATA[<div>]>]]>", where the CDATA_CONTENT is "<div>]>" text2 -> "]]>>]" The reason why start_tag is NOT "<DIV>>>" is because of the rule 6. The reason why cdata is NOT "<![CDATA[<div>]>]]>]]>" is because of the rule 7.
Example 3:
Input: code = "<A> <B> </A> </B>" Output: false Explanation: Unbalanced. If "<A>" is closed, then "<B>" must be unmatched, and vice versa.
Constraints:
1 <= code.length <= 500
code
consists of English letters, digits, '<'
, '>'
, '/'
, '!'
, '['
, ']'
, '.'
, and ' '
.This problem requires validating a code snippet based on a set of rules related to HTML-like tags. The solution uses a stack to keep track of open tags, ensuring that all tags are properly closed and nested.
Approach:
The solution iterates through the input string code
. It uses a state machine-like approach to handle different scenarios:
CDATA Sections: It checks for CDATA sections (<![CDATA[ ... ]]>
). If found, it skips over the content within the CDATA section, as it's not parsed as tags.
Closing Tags: It looks for closing tags (</...>
). If found, it verifies:
Opening Tags: It checks for opening tags (<...>
). If found, it verifies:
Invalidity Checks: It performs several checks to ensure validity:
<
and >
are properly matched.Time Complexity Analysis:
The solution iterates through the input string once. The operations within the loop (string comparisons, stack operations) take constant time O(1) relative to the input size. Therefore, the overall time complexity is O(n), where n is the length of the input string code
.
Space Complexity Analysis:
The space complexity is determined by the maximum size of the stack, which is proportional to the maximum depth of nested tags. In the worst case, all tags might be nested, leading to a stack size proportional to the input size. Thus, the space complexity is O(n) in the worst case, though it's often much less in practice.
Code Explanations (Python3 as example):
The Python3 code uses a function check
to validate tag names and the main function iterates through the code, checking for CDATA sections, closing tags, and opening tags as described above. The stack stk
keeps track of open tags. The code returns True
if all checks pass and False
otherwise.
The other language solutions (Java, C++, Go, and Rust) follow the same approach but differ in their syntax and standard library usage. They all maintain the same time and space complexity as the Python solution. The core logic remains consistent.