forked from fishercoder1534/Leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
_591.java
153 lines (114 loc) · 5.29 KB
/
_591.java
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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package com.fishercoder.solutions;
import java.util.ArrayDeque;
import java.util.Deque;
/**
* 591. Tag Validator
*
* Given a string representing a code snippet,
* you need to 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:
1. The code must be wrapped in a valid closed tag. Otherwise, the code is invalid.
2. A closed tag (not necessarily valid) has exactly the following format : <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.
3. A valid TAG_NAME only contain upper-case letters, and has length in range [1,9]. Otherwise, the TAG_NAME is invalid.
4. A valid 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.
5. A start tag is unmatched if no end tag exists with the same TAG_NAME, and vice versa.
However, you also need to consider the issue of unbalanced when tags are nested.
6. A < 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).
7. The cdata has the following format : <![CDATA[CDATA_CONTENT]]>.
The range of CDATA_CONTENT is defined as the characters between <![CDATA[ and the first subsequent ]]>.
8. 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.
Valid Code Examples:
Input: "<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 unmatched start tag with invalid TAG_NAME, it should be considered as plain text, not parsed as tag.
So TAG_CONTENT is valid, and then the code is valid. Thus return true.
Input: "<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.
Invalid Code Examples:
Input: "<A> <B> </A> </B>"
Output: False
Explanation: Unbalanced. If "<A>" is closed, then "<B>" must be unmatched, and vice versa.
Input: "<DIV> div tag is not closed <DIV>"
Output: False
Input: "<DIV> unmatched < </DIV>"
Output: False
Input: "<DIV> closed tags with invalid tag name <b>123</b> </DIV>"
Output: False
Input: "<DIV> unmatched tags with invalid tag name </1234567890> and <CDATA[[]]> </DIV>"
Output: False
Input: "<DIV> unmatched start tag <B> and unmatched end tag </C> </DIV>"
Output: False
Note:
For simplicity, you could assume the input code (including the any characters mentioned above)
only contain letters, digits, '<','>','/','!','[',']' and ' '.
*/
public class _591 {
/**Credit: https://discuss.leetcode.com/topic/91300/java-solution-use-startswith-and-indexof*/
public boolean isValid(String code) {
Deque<String> stack = new ArrayDeque<>();
for (int i = 0; i < code.length(); ) {
if (i > 0 && stack.isEmpty()) {
return false;
}
if (code.startsWith("<![CDATA[", i)) {
int j = i + 9;//"<![CDATA[" length is 9
i = code.indexOf("]]>", j);
if (i < 0) {
return false;
}
i += 3;//"]]>" length is 3
} else if (code.startsWith("</", i)) {
int j = i + 2;
i = code.indexOf(">", j);
if (i < 0 || i == j || i - j > 9) {
return false;
}
for (int k = j; k < i; k++) {
if (!Character.isUpperCase(code.charAt(k))) {
return false;
}
}
String s = code.substring(j, i++);
if (stack.isEmpty() || !stack.pop().equals(s)) {
return false;
}
} else if (code.startsWith("<", i)) {
int j = i + 1;
i = code.indexOf(">", j);
if (i < 0 || i == j || i - j > 9) {
return false;
}
for (int k = j; k < i; k++) {
if (!Character.isUpperCase(code.charAt(k))) {
return false;
}
}
String s = code.substring(j, i++);
stack.push(s);
} else {
i++;
}
}
return stack.isEmpty();
}
}