This page explains Java solution to problem Tag Validator
using String
data structure.
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:
<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.[1,9]
. Otherwise, the TAG_NAME is invalid.<
, 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[ and the first subsequent ]]>.
Example 2:Input: <DIV>This is the first line <![CDATA[<div>]]></DIV>
Output: True
Input: "<A> <B> </A> </B>"
Output: False
package com.vc.hard;
import java.util.*;
class TagValidator {
private int index = 0;
private String CDATA_PREFIX_START = "<![CDATA[";
private String CDATA_PREFIX_END = "]]>";
private String OPENING_TAG_START = "<";
private String OPENING_TAG_END = ">";
private String CLOSING_TAG_START = "</";
private String CLOSING_TAG_END = ">";
public boolean isValid(String code) {
Stack<String> st = new Stack<>();
int n = code.length();
while(index < n) {
if(index > 0 && st.isEmpty()) return false;
else if(code.startsWith(CDATA_PREFIX_START, index)) {
if(!processCDATA(code)) return false;
}
else if(code.startsWith(CLOSING_TAG_START, index)) {
if(!isValidClosingTag(code, st)) return false;
}
else if(code.startsWith(OPENING_TAG_START, index)) {
if(!isValidOpeningTag(code, st)) return false;
}
else index++;
}
return st.isEmpty();
}
private boolean processCDATA(String code) {
int start = code.indexOf(CDATA_PREFIX_START, index);
int end = code.indexOf(CDATA_PREFIX_END, start + CDATA_PREFIX_START.length());
if(start != -1 && end != -1) {
index = end + CDATA_PREFIX_END.length();
return true;
}
return false;
}
private boolean isValidOpeningTag(String code, Stack st) {
int start = code.indexOf(OPENING_TAG_START, index);
int end = code.indexOf(OPENING_TAG_END, start + OPENING_TAG_START.length());
if(start != -1 && end != -1) {
String tagName = code.substring(start + 1, end);
if(tagName.length() <= 9
&& tagName.length() >= 1
&& containsUpper(tagName)) {
st.push(tagName);
index = end + OPENING_TAG_END.length();
return true;
}
}
return false;
}
private boolean isValidClosingTag(String code, Stack st) {
int start = code.indexOf(CLOSING_TAG_START, index);
int end = code.indexOf(CLOSING_TAG_END, start + CLOSING_TAG_START.length());
if(start != -1 && end != -1) {
String tagName = code.substring(start + 2, end);
if(tagName.length() <= 9
&& tagName.length() >= 1
&& containsUpper(tagName)
&& !st.isEmpty()
&& st.pop().equals(tagName)) {
index = end + CLOSING_TAG_END.length();
return true;
}
}
return false;
}
private boolean containsUpper(String tagName) {
for(int i = 0; i < tagName.length(); i++) {
if(!(tagName.charAt(i) >= 'A' && tagName.charAt(i) <= 'Z')) return false;
}
return true;
}
}
O(N) Where
N is length of input string
O(N) Where
N is length of input string