【月度刷题计划同款极致繁琐的模拟题

2023年 7月 25日 45.5k 0

题目描述

这是 LeetCode 上的 591. 标签验证器 ,难度为 困难。

Tag : 「模拟」、「栈」

给定一个表示代码片段的字符串,你需要实现一个验证器来解析这段代码,并返回它是否合法。合法的代码片段需要遵守以下的所有规则:

  • 代码必须被合法的闭合标签包围。否则,代码是无效的。
  • 闭合标签(不一定合法)要严格符合格式:TAG_CONTENT。其中, 是起始标签, 是结束标签。起始和结束标签中的 TAG_NAME 应当相同。当且仅当 TAG_NAMETAG_CONTENT 都是合法的,闭合标签才是合法的。
  • 合法的 TAG_NAME 仅含有大写字母,长度在范围 [1,9][1,9][1,9] 之间。否则,该 TAG_NAME 是不合法的。
  • 合法的 TAG_CONTENT 可以包含其他合法的闭合标签,cdata ( 请参考规则 777 )和任意字符( 注意参考规则 111 )除了不匹配的 CDATA_CONTENT 的范围被定义成  和后续的第一个 ]]>之间的字符。
  • CDATA_CONTENT 可以包含任意字符。cdata 的功能是阻止验证器解析 CDATA_CONTENT,所以即使其中有一些字符可以被解析为标签(无论合法还是不合法),也应该将它们视为常规字符。
  • 合法代码的例子:

    输入: "This is the first line ]]>"
    
    输出: True
    
    解释: 
    
    代码被包含在了闭合的标签内:  和  。
    
    TAG_NAME 是合法的,TAG_CONTENT 包含了一些字符和 cdata 。 
    
    即使 CDATA_CONTENT 含有不匹配的起始标签和不合法的 TAG_NAME,它应该被视为普通的文本,而不是标签。
    
    所以 TAG_CONTENT 是合法的,因此代码是合法的。最终返回True。
    
    
    输入: ">>  ![cdata[]] ]>]]>]]>>]"
    
    输出: True
    
    解释:
    
    我们首先将代码分割为: start_tag|tag_content|end_tag 。
    
    start_tag -> ""
    
    end_tag -> ""
    
    tag_content 也可被分割为: text1|cdata|text2 。
    
    text1 -> ">>  ![cdata[]] "
    
    cdata -> "]>]]>" ,其中 CDATA_CONTENT 为 "]>"
    
    text2 -> "]]>>]"
    
    
    start_tag 不是 ">>" 的原因参照规则 6 。
    cdata 不是 "]>]]>]]>" 的原因参照规则 7 。
    

    不合法代码的例子:

    输入: "      "
    输出: False
    解释: 不合法。如果 "" 是闭合的,那么 "" 一定是不匹配的,反之亦然。
    
    输入: "  div tag is not closed  "
    输出: False
    
    输入: "  unmatched <  "
    输出: False
    
    输入: " closed tags with invalid tag name  123 "
    输出: False
    
    输入: " unmatched tags with invalid tag name   and   "
    输出: False
    
    输入: "  unmatched start tag   and unmatched end tag   "
    输出: False
    

    注意:

    • 为简明起见,你可以假设输入的代码(包括提到的任意字符)只包含数字, 字母, '','/','!','[',']'' '

    模拟(栈)

    字符串大模拟,假设字符串 s 长度为 nnn,当前处理到的位置为 iii,根据以下优先级进行检查:

  • 优先尝试检查以 iii 为开始的连续段是否为 CDATA,若能匹配到开头,则尝试匹配到 CDATA 的结尾处,并更新 iii,若无法找到结尾,返回 False
  • 尝试匹配 s[i]s[i]s[i] 是否为 , CDATA2 = "]]>";
    public boolean isValid(String s) {
    Deque d = new ArrayDeque();
    int n = s.length(), i = 0;
    while (i < n) {
    if (i + 8 < n && s.substring(i, i + 9).equals(CDATA1)) {
    if (i == 0) return false;
    int j = i + 9;
    boolean ok = false;
    while (j < n && !ok) {
    if (j + 2 < n && s.substring(j, j + 3).equals(CDATA2)) {
    j = j + 3; ok = true;
    } else {
    j++;
    }
    }
    if (!ok) return false;
    i = j;
    } else if (s.charAt(i) == '') {
    if (!Character.isUpperCase(s.charAt(j))) return false;
    j++;
    }
    if (j == n) return false;
    int len = j - p;
    if (len 9) return false;
    String tag = s.substring(p, j);
    i = j + 1;
    if (!isEnd) {
    d.addLast(tag);
    } else {
    if (d.isEmpty() || !d.pollLast().equals(tag)) return false;
    if (d.isEmpty() && i < n) return false;
    }
    } else {
    if (i == 0) return false;
    i++;
    }
    }
    return d.isEmpty();
    }
    }

    • 时间复杂度:O(n)O(n)O(n)
    • 空间复杂度:O(n)O(n)O(n)

    最后

    这是我们「刷穿 LeetCode」系列文章的第 No.591 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。

    在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。

    为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:github.com/SharingSour… 。

    在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

    更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

  • 相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论