【每日一题】Leetcode - 10. 正则表达式匹配

news2024/12/24 11:38:52

题目

Leetcode - 10. 正则表达式匹配

解题思路

  • 预处理正则表达式,合并同项,比如: "a * b * c * . * " -> " . * "
  • 更加预处理后的正则表达式,构建NFA
  • 通过NFA状态转移条件一个一个匹配字符串字符
  • 不匹配的状态要回退
  • 匹配完字符串了,且该状态是可结束的,就true,否则false

c * b * a * 这种正则,构造NFA时,标记a是可结束,但是其实c, b也可结束
a * b * c 这种正则,构造NFA时,a和b都可以是c的父节点

class Solution {

    public boolean isMatch(String s, String p) {
        if (p.equals(".*")) {
            return true;
        }

        //  pretreatment pattern
        p = pretreatment(p);
        if (p.equals(".*")) {
            return true;
        }

        //  constructNFA
        State root = constructNFA(p);
        //  match s
        Set<State> states = matchStates(root, s.charAt(0));
        for (State state : states) {
            boolean flag = doMatch(s, 0, state);
            if (flag) {
                return true; // it has any one matched
            }
        }
        return false;
    }

    private static class State {
        //  this state's parents
        Set<State> parents = new HashSet<>();
        //  <condition, states> : the table denotes map to next state by condition
        Map<Character, Set<State>> nextStates = new HashMap<>();
        //  this state is last state
        boolean isEnd = false;
    }

    private String pretreatment(String p) {
        //  pretreatment pattern
        //  merge follow pattern
        //      a* b* ... c*.* -> .*
        //      a* a* ... a*a* -> a*
        //      .* a* ... .*b* -> .*
        char[] preP = new char[p.length()];
        int prePIndex = -1;
        for (int i = 0; i < p.length(); i++) {
            char ch = p.charAt(i);
            preP[++prePIndex] = ch;
            if (ch != '*') {
                continue;
            }
            // .*
            if (p.charAt(i - 1) == '.') { // .* a* ... .*b* -> .*
                while (i + 2 < p.length() && p.charAt(i + 2) == '*') {
                    i += 2;
                }
                continue;
            }
            //  a*
            int j = i;
            boolean flag = false;
            while (j + 2 < p.length() && p.charAt(j + 2) == '*') {
                if (p.charAt(j + 1) == '.') {
                    flag = true;
                    break;
                }
                j += 2;
            }
            if (flag) { //  a* b* ... c*.* -> .*
                preP[prePIndex - 1] = '.';
                i = j + 2;
                while (i + 2 < p.length() && p.charAt(i + 2) == '*') {
                    i += 2;
                }
                continue;
            }
            //  a* a* ... a*a* -> a*
            while (i + 2 < p.length() && p.charAt(i + 2) == '*') {
                if (p.charAt(i + 1) != preP[prePIndex - 1]) {
                    break;
                }
                i += 2;
            }
        }
        p = new String(preP, 0, prePIndex + 1);
        return p;
    }

    private State constructNFA(String p) {
        State newState = new State();
        State root = newState;
        for (int i = 0; i < p.length(); i++) {
            char ch = p.charAt(i);
            Set<State> states;
            if (ch != '*') {
                states = root.nextStates.computeIfAbsent(ch, k -> new HashSet<>());
                State state = new State();
                states.add(state);

                if (i >= 1 && p.charAt(i - 1) == '*') {
                    repeatedParentAddState(root, ch, state);
                }
                state.parents.add(root);
                root = state;
                if (i == p.length() - 1) {
                    root.isEnd = true;
                }
                continue;
            }
            //  x* -> get x
            ch = p.charAt(i - 1);
            states = root.nextStates.computeIfAbsent(ch, k -> new HashSet<>());
            states.add(root); // x+ : contain one and more one
            root.parents.add(root); // x{0} : no contain
            //  before two steps achieve x*
            if (i == p.length() - 1) {
                root.isEnd = true;
                repeatedParentMarkEnd(root);
            }
        }
        return newState;
    }

    public boolean doMatch(String s, int cur, State state) {
        if (cur + 1 == s.length()) {
            return state.isEnd;
        }
        Set<State> states = matchStates(state, s.charAt(cur + 1));
        for (State state1 : states) {
            boolean flag = doMatch(s, cur + 1, state1);
            if (flag) {
                return true;
            }
        }
        return false;
    }

    public Set<State> matchStates(State root, char ch) {
        //  get states by condition
        Set<State> states = root.nextStates.get(ch);
        if (states == null) {
            states = new HashSet<>();
        }
        //  get states by especial condition of '.', because it can match any char
        Set<State> states1 = root.nextStates.get('.');
        if (states1 != null) {
            states.addAll(states1);
        }
        return states;
    }

    private void repeatedParentMarkEnd(State root) {
        if (!root.parents.contains(root)) {
            return;
        }
        for (State parent : root.parents) {
            if (parent == root) {
                continue;
            }
            parent.isEnd = true;
            repeatedParentMarkEnd(parent);
        }
    }

    private void repeatedParentAddState(State root, char ch, State state) {
        if (!root.parents.contains(root)) {
            return;
        }
        for (State rootParent : root.parents) {
            Set<State> states = rootParent.nextStates.get(ch);
            if (states != null) {
                if (states.contains(state)) {
                    continue;
                }
                states.add(state);
            }
            else {
                states = new HashSet<>();
                states.add(state);
                rootParent.nextStates.put(ch, states);
            }
            repeatedParentAddState(rootParent, ch, state);
        }
    }
    
}

在这里插入图片描述

优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/697530.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【统一安全管控平台】4A解析

文章目录 一、统一帐号&#xff08;Account&#xff09;二、统一认证(Authentication)三、统一授权(Authorization)四、统一审计(Audit)参考&感谢 4A是指帐号&#xff08;Account&#xff09;、认证&#xff08;Authentication&#xff09;、授权&#xff08;Authorization…

mysql8.0新特性详解

一、my.ini或my.cnf的全局参数 一个连接最少占用内存是256K&#xff0c;最大是64M&#xff0c;如果一个连接的请求数据超过64MB&#xff08;比如排序&#xff09;&#xff0c;就会申请临时空间&#xff0c;放到硬盘上。 #最大连接数 max_connections3000 #最大用户连接数 max_…

智能饮品机器人的市场现状与前景未来,点赋科技与您共同期待

引言&#xff1a; 近年来&#xff0c;智能饮品机器人行业迅猛发展&#xff0c;成为引人瞩目的新兴市场。然而&#xff0c;这个行业的市场现状到底如何&#xff1f;它的前景又将如何发展&#xff1f;让点赋科技带大家一起来看看。 市场现状&#xff1a; 智能饮品机器人市场在过去…

解锁高效部署!快速搭建Kubernetes集群,提升团队生产力!

1 MacOS 1.1 下载 docker-desktop 从 docker 下载 docker-desktop (opens new window)&#xff0c;并完成安装 1.2 启用 k8s 集群 启动 docker-desktop&#xff0c;打开preference 面板 切换到 Kubernetes 标签页&#xff0c;并勾选启动 Enable Kubernetes&#xff0c;点击…

nginx 入门 (b站IT楠老师学习笔记)

文章目录 Nginx 入门 &#xff08;b站IT楠老师学习笔记&#xff09;一 基础了解1、下载nginx安装包2. nginx 可以提供的服务3. nginx 的优点4. 应用场景 二 实战2.1 基础检查以及配置文件结构了解2.2 main全局配置2.3 events模块2.4 http服务器配置2.5虚拟主机配置详解2.5.1 ht…

el-pagination分页查询封装

需求&#xff1a;因为需要用到表单查询的地方太多了&#xff0c;所以为了避免每个页面都写分页组件&#xff0c;直接封装好调用就完事了&#xff0c;简简单单 1.创建Pigination.vue公用组件 <template><div :class"{hidden:hidden}" class"paginatio…

AD中修改一个元器件的所有焊盘大小

1.首先&#xff0c;选中其中一个焊盘。 2.查找相似对象 3.修改component为same 4.修改X size和Y size为same 5.确定 6.修改Pad Stack中的x/y 注&#xff1a;component可以不用改为same&#xff0c;用any就是查找和这个焊盘大小类似的对象。

力扣1768.交替合并字符串(java模拟法)

题目描述&#xff1a; 给你两个字符串 word1 和 word2 。请你从 word1 开始&#xff0c;通过交替添加字母来合并字符串。如果一个字符串比另一个字符串长&#xff0c;就将多出来的字母追加到合并后字符串的末尾。 返回 合并后的字符串 。 问题分析&#xff1a; 我们可以直…

servlet 监听器

做法: 在web.xml中: 或

矩形中的正方形:探究力扣最大正方形问题的奥秘

本篇博客会讲解力扣“1725. 可以形成最大正方形的矩形数目”的解题思路&#xff0c;这是题目链接。 本题的思路是&#xff1a;对于每一个矩形&#xff0c;切分出来的最大正方形的边长是矩形的长和宽的较小值。我们需要维护最大的正方形边长&#xff0c;并统计数目。 我们可以写…

Verilog基础之十、计数器实现

目录 一、前言 二、工程设计 2.1 设计代码 2.2 综合结果 ​2.3 仿真结果 一、前言 计数器是较为基础的逻辑&#xff0c;很多其他逻辑可依靠计数器实现&#xff0c;如控制器&#xff0c;分频。原理为通过统计时钟脉冲的个数来输出计数值。 二、工程设计 2.1 设计代码 工…

实验 09 线性回归与波士顿房价预测

文章目录 实验 09 线性回归与波士顿房价预测一、实验目的二、实验设备三、实验内容3.1 了解数据3.2 分析数据3.3 建立模型&#xff08;一&#xff09;使用一个变量进行预测&#xff08;二&#xff09;使用多元线性回归分析进行预测 实验 09 线性回归与波士顿房价预测 一、实验…

Dubbo【Dubbo实战(整合Mybaits-plus配置、接口、集成Thymeleaf) 】(五)-全面详解(学习总结---从入门到深化)

目录 ​编辑 Dubbo实战_整合Mybaits-plus配置 Dubbo实战_创建添加用户接口 Dubbo实战_查询用户业务接口 Dubbo实战_更新用户业务接口 Dubbo实战_删除用户业务接口 Dubbo实战_集成Thymeleaf Dubbo实战_用户添加业务消费者实现 Dubbo实战_用户查询业务消费者实现 Dubbo实战_…

R带参数运行

rm(listls()) suppressPackageStartupMessages({library(getopt) })# getopt(),是getopt包的函数&#xff0c;需要先按照getopt包 # # getopt(spec NULL, opt commandArgs(TRUE),command get_Rscript_filename(), usage FALSE,debug FALSE) # # spec&#xff1a;一个4或…

linux suse12 安装mysql

1.下载mysql https://dev.mysql.com/downloads/mysql/ 2.选中mysql版本 对选中的版本进行下载 也可以在linux服务器上直接下载&#xff1a;wget -c https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.21-linux-glibc2.12-x86_64.tar.xz 3.把下载好的文件放到/usr/local…

mac上的vscode设置用滚轮来调节编辑页面大小

mac上的vscode设置用滚轮来调节编辑页面大小 问题背景 今天在mac上安装了vscode&#xff0c;刚想编写代码&#xff0c;但是突然发现无法用ctrl鼠标的滚轮来进行控制 代码编辑区域字体的大小。 解决方法 经过查找资料&#xff0c;发现在设置的配置文件中&#xff0c;有一个配…

前后端分离模式开发的BS电子病历编辑器源码(Java)

电子病历系统&#xff0c;是医学专用系统。医院通过电子病历以电子化方式记录患者就诊的信息&#xff0c;包括&#xff1a;首页、病程记录、检查检验结果、医嘱、手术记录、护理记录等等&#xff0c;其中既有结构化信息&#xff0c;也有非结构化的自由文本&#xff0c;还有图形…

HOT19-螺旋矩阵

leetcode原题链接&#xff1a;螺旋矩阵 题目描述 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例…

通过USB和wifi连接真机编写第一个脚本

目录 一、连接手机 1、通过usb数据线连接手机 2、无线连接手机 二、编写第一个脚本 一、连接手机 1、通过usb数据线连接手机 数据线连接手机并允许调试 cmd命令行执行&#xff1a; adb devices 如果没有显示device信息&#xff0c;请检查&#xff1a; 手机是否开启usb调…

element的时间控件默认值为当前时间

vue代码 <el-form-item label"验收时间" prop"checkAcceptTime"><el-date-picker clearablev-model"form.checkAcceptTime"type"datetime"value-format"yyyy-MM-dd HH:mm:ss"placeholder"请选择验收时间"…