Skip to content

Commit 614d201

Browse files
committed
Add solution #591
1 parent 9855a42 commit 614d201

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,7 @@
458458
587|[Erect the Fence](./0587-erect-the-fence.js)|Hard|
459459
589|[N-ary Tree Preorder Traversal](./0589-n-ary-tree-preorder-traversal.js)|Easy|
460460
590|[N-ary Tree Postorder Traversal](./0590-n-ary-tree-postorder-traversal.js)|Easy|
461+
591|[Tag Validator](./0591-tag-validator.js)|Hard|
461462
594|[Longest Harmonious Subsequence](./0594-longest-harmonious-subsequence.js)|Easy|
462463
599|[Minimum Index Sum of Two Lists](./0599-minimum-index-sum-of-two-lists.js)|Easy|
463464
605|[Can Place Flowers](./0605-can-place-flowers.js)|Easy|

solutions/0591-tag-validator.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* 591. Tag Validator
3+
* https://leetcode.com/problems/tag-validator/
4+
* Difficulty: Hard
5+
*
6+
* Given a string representing a code snippet, implement a tag validator to parse the code and
7+
* return whether it is valid.
8+
*
9+
* A code snippet is valid if all the following rules hold:
10+
* 1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
11+
* 2. A closed tag (not necessarily valid) has exactly the following format:
12+
* <TAG_NAME>TAG_CONTENT</TAG_NAME>. Among them, <TAG_NAME> is the start tag, and </TAG_NAME>
13+
* is the end tag. The TAG_NAME in start and end tags should be the same. A closed tag is valid
14+
* if and only if the TAG_NAME and TAG_CONTENT are valid.
15+
* 3. A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise,
16+
* the TAG_NAME is invalid.
17+
* 4. A valid TAG_CONTENT may contain other valid closed tags, cdata and any characters (see
18+
* note1) EXCEPT unmatched <, unmatched start and end tag, and unmatched or closed tags with
19+
* invalid TAG_NAME. Otherwise, the TAG_CONTENT is invalid.
20+
* 5. A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa.
21+
* However, you also need to consider the issue of unbalanced when tags are nested.
22+
* 6. A < is unmatched if you cannot find a subsequent >. And when you find a < or </, all
23+
* the subsequent characters until the next > should be parsed as TAG_NAME (not necessarily
24+
* valid).
25+
* 7. The cdata has the following format : <![CDATA[CDATA_CONTENT]]>. The range of CDATA_CONTENT
26+
* is defined as the characters between <![CDATA[ and the first subsequent ]]>.
27+
* 8. CDATA_CONTENT may contain any characters. The function of cdata is to forbid the validator
28+
* to parse CDATA_CONTENT, so even it has some characters that can be parsed as tag (no matter
29+
* valid or invalid), you should treat it as regular characters.
30+
*/
31+
32+
/**
33+
* @param {string} code
34+
* @return {boolean}
35+
*/
36+
var isValid = function(code) {
37+
const stack = [];
38+
39+
for (let i = 0; i < code.length;) {
40+
if (i > 0 && !stack.length) {
41+
return false;
42+
}
43+
if (code.startsWith('<![CDATA[', i)) {
44+
const j = i + 9;
45+
i = code.indexOf(']]>', j);
46+
if (i === -1) {
47+
return false;
48+
}
49+
i += 3;
50+
} else if (code.startsWith('</', i)) {
51+
const j = i + 2;
52+
i = code.indexOf('>', j);
53+
if (i === -1) {
54+
return false;
55+
}
56+
const tag = code.slice(j, i);
57+
if (!stack.length || stack.pop() !== tag || !/^[A-Z]{1,9}$/.test(tag)) {
58+
return false;
59+
}
60+
i++;
61+
} else if (code[i] === '<') {
62+
const j = i + 1;
63+
i = code.indexOf('>', j);
64+
if (i === -1) {
65+
return false;
66+
}
67+
const tag = code.slice(j, i);
68+
if (!/^[A-Z]{1,9}$/.test(tag)) {
69+
return false;
70+
}
71+
stack.push(tag);
72+
i++;
73+
} else {
74+
i++;
75+
}
76+
}
77+
78+
return !stack.length;
79+
};

0 commit comments

Comments
 (0)