10. Regular Expression Matching

Given an input string (s) and a pattern (p), implement regular expression matching with support for '.' and '*'.

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Note:

  • s could be empty and contains only lowercase letters a-z.
  • p could be empty and contains only lowercase letters a-z, and characters like . or *.

Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".

Example 2:

Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".

Example 3:

Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".

Example 4:

Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".

Example 5:

Input:
s = "mississippi"
p = "mis*is*p*."

Output: false

一直在用正则表达式,那么是否有考虑过正则表达式是匹配是怎么实现的呢?现在这题就是正则的部分规则体现,试试能不能自己写一个正则表达式。

题目:给你两个字符串s 和 p,实现正则表达式的 "."和"*"的匹配规则

注:"."表示匹配任意字符,"*"表示匹配*前面那字符出现任意次数。


我靠,这还不简单?噼里啪啦,三两行代码完事。

public static boolean isMatch(String s, String p) {
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(p);
        return pattern.matcher(s).matches();
}
皮这一下就很开心,但是开心之后呢?人家是怎么实现的呢?


先提供一些测试数据

    private static String[][] ss = {
            {"aaa", "a*a"},{"ab", ".*c"},{"", "bab"}, {"aa", "a*"}, {"ab", ".*.."},
            {"aaa", "aaaa"}, {"", ".*"}, {"aab", "cab"}, {"aaaa", "aaa"}, {"aab", "c*a*b"},
            {"", "a*a*"}
    };
    
    private static boolean[] result = {true, false, false, true, true,
            false, true, false, false, true, true,
            true};

    public static void main(String[] args){
        if (false){
            System.out.print(isMatch(ss[10][0], ss[10][1]));
        }else {
            for (int i = 0; i < ss.length; i++) {
                try {
                    if (isMatch(ss[i][0], ss[i][1]) ^ result[i]){
                        System.out.println("索引为" + i + "的数据出错");
                        return;
                    }
                }catch (Exception e){
                    System.out.println("索引为" + i + "的数据出现异常");
                    return;
                }
            }
            System.out.print("结束,全部校验通过");
        }
    }

说来惭愧,写的过程不断调试,增加判断,过程中还换了一个思路去写,还是参考了LeetCode中的解决方案,最终才写完了下面的代码通过了测试。

最后的结果也是很惭愧的。


再来一个对比比较鲜明的,系统的正则表达式通过测试的速度。


速度看上去是差不多的,但是架不住人家的功能强大啊,而我这个仅仅就支持了"." "*"这样一对比就根本没可比性了。好了,废话少说,先分享一下解题思路吧,老规矩,先上代码。

public static boolean isMatch(String s, String p) {

        if (s.isEmpty()) return p.isEmpty() || (p.length() >= 2 && p.charAt(1) == '*' && isMatch(s, p.substring(2)));

        if (p.length() > 1 && p.charAt(1) == '*'){
            if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
                return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
            }else {
                return isMatch(s, p.substring(2));
            }
        }else {
            if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
                return isMatch(s.substring(1), p.substring(1));
            }else {
                return false;
            }
        }
    }

抓住一个核心思想,就是目标值S和匹配规则P完全匹配上了,就返回True,否则在这个过程中出现了不匹配,那么就表示没有匹配上。


点击查看更多解题思路



下面聊聊写这个方法的心路历程吧,分享一下思考问题的方式,多是一些废话,各路大神没有兴趣就不用往下看了。

根据这个思路,出现了下面的代码,然后利用测试数据 "aaa", "a*a"进行测试时发现并不能匹配上。

public static boolean isMatch(String s, String p) {

        if (s.isEmpty()) return p.isEmpty();

        if (p.length() > 1 && p.charAt(1) == '*'){
            if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
                return isMatch(s.substring(1), p);
            }else {
                return isMatch(s, p.substring(2));
            }
        }else {
            if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
                return isMatch(s.substring(1), p.substring(1));
            }else {
                return false;
            }
        }
    }

于是一顿跟踪调试,发现如果只是这样匹配,匹配规则P是无法匹配完全的,于是将代码继续进化

public static boolean isMatch(String s, String p) {

        if (s.isEmpty()) return p.isEmpty();

        if (p.length() > 1 && p.charAt(1) == '*'){
            if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
                return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
            }else {
                return isMatch(s, p.substring(2));
            }
        }else {
            if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
                return isMatch(s.substring(1), p.substring(1));
            }else {
                return false;
            }
        }
    }

如果前两个匹配是 x*的时候无法将s匹配完,那么就用下一组继续匹配,如果不是x*的模式,那么就表示s和p不匹配。然后继续测试,{"", "bab"}就遇到了这两个数。又是一顿调试,进化代码

public static boolean isMatch(String s, String p) {

        if (s.isEmpty()) return p.isEmpty() || p.length() == 2 && p.charAt(1) == '*';

        if (p.length() > 1 && p.charAt(1) == '*'){
            if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
                return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
            }else {
                return isMatch(s, p.substring(2));
            }
        }else {
            if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
                return isMatch(s.substring(1), p.substring(1));
            }else {
                return false;
            }
        }
    }

当s已经匹配完全了,如果p的最后一个字符是*那么就表示能够匹配上。继续调试遇到了{"aab", "c*a*b"}这俩兄弟,继续递归优化代码,首先发现了p.length()他不一定就只有一组x*的字符啊,所以将p.length() == 2 && p.charAt(1) == '*' 改为 p.length() >= 2 && p.charAt(1) == '*',接着测试{"ab", ".*c"}这哥俩又来了,于是出现了上面那段代码。


### Flink 大数据处理优化技巧与最佳实践 #### 调优原则与方法概述 对于Flink SQL作业中的大状态导致的反压问题,调优的核心在于减少状态大小以及提高状态访问效率。通过合理配置参数和调整逻辑设计可以有效缓解此类瓶颈[^1]。 #### 参数设置建议 针对不同版本下的具体特性差异,在实施任何性能改进措施前应当充分理解当前使用的Flink版本特点及其局限性;同时也要考虑特定应用场景的需求特征来定制化解决方案。这包括但不限于并行度设定、内存分配策略等方面的选择[^2]。 #### 数据流模式优化 采用广播变量机制可作为一种有效的手段用于降低主数据流转过程中所需维护的状态量级。当存在一对多关系的数据集间需频繁交互时,将较小规模的一方作为广播状态保存下来供另一方查询匹配使用不失为明智之举。此方式特别适用于维表Join操作中,其中一方变动相对较少但又必须保持最新记录的情况[^3]。 ```sql -- 创建临时视图以支持后续JOIN操作 CREATE TEMPORARY VIEW dim_table AS SELECT * FROM kafka_source; -- 定义Temporal Table Function以便获取指定时间点上的历史快照 CREATE FUNCTION hist_dim_table AS 'com.example.HistoricalDimTableFunction'; -- 执行带有时态条件约束的JOIN语句 SELECT o.order_id, d.product_name FROM orders o LEFT JOIN LATERAL TABLE(hist_dim_table(o.event_time)) AS d ON o.product_id = d.id; ``` 上述代码片段展示了如何利用Flink SQL实现基于时间戳的历史维度表连接功能,从而确保每次都能准确捕捉到事件发生瞬间对应的最恰当的产品名称信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值