可视化LeetCode正则表达式问题中的重叠子问题以及DP的使用

时间:2018-10-30 02:38:11

标签: java python string recursion dynamic-programming

我刚刚使用递归在leetcode.com上解决了this问题(10.正则表达式匹配)。我能够理解递归解决方案。但是,当我看到此代码的优化版本时,建议我使用动态编程。我不明白为什么我们在这里需要动态编程?

  • 我看不到这个问题有重叠的子问题。为什么我们要使用记忆或制表法?我无法看到重叠的子问题。
  • 这是我到目前为止到达的地方。这是我的解决方案:

     public static boolean isMatch(String text, String pattern) {
    
    if (pattern.isEmpty())
        return text.isEmpty();
    boolean first_match = (!text.isEmpty() && (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));
    
    if (pattern.length() >= 2 && pattern.charAt(1) == '*') {
        return isMatch(text, pattern.substring(2))|| first_match && isMatch(text.substring(1), pattern);
    } else {
        return first_match && isMatch(text.substring(1), pattern.substring(1));
    }
    

我对递归解决方案的理解是,我可以看到模式中的下一个字符是否为*,那么可能有两种情况:

  1. 我们跳过当前字符以及下一个字符(*),并从索引2中提取模式的子字符串,并将模式的剩余子字符串与当前文本匹配。这表示*前面的字符出现'0'。
  2. 模式中的*将继续吸收文本中的匹配字符。只要我们保持相同的性格,他们就不断匹配星星,我们就会继续前进。

另一种情况是,如果下一个字符不是'*',则我们检查当前字符是否匹配,如果是,则检查两个字符的其余子字符串。

我尝试使用:

  

输入:   s =“密西西比州”   p =“ mis * is * p *”。   输出:false

我可以先想象一下 m和m匹配, 我和我比赛 (到目前为止是线性递归)。 现在开始复杂的部分,因为s和s匹配,但是s的下一个字符是星号。如果我调用,则将场景1中匹配的'0'出现作为场景2并将*中的匹配字符作为场景2进行吸收,那么递归调用将如下所示:

  

场景1:文本为ssissippi,其余模式为 p

     

s和i字符不匹配

     

方案2:其余文本为sissippi,模式为s is p *。

     

方案1:文本为sissippi,其余模式为 p

     

s和i字符不匹配

     

方案2:剩余文本为issippi,模式为s is p *。

     

方案1:文本为issippi,其余模式为 p

     

个字符匹配,因此下一个递归调用与文本:ssippi和   模式为:s p

     

方案1:文本为ssippi,其余模式为p *。

     

方案1:文本为ssippi,其余模式为。

     

个字符匹配,因此下一个递归调用与文本:sippi和   模式为:

     

方案2:剩余文字为sippi,样式为p *。

     

方案2:其余文本为sippi,模式为s p

     

方案1:文本为sippi,其余模式为p *。

     

方案1:文本为sippi,其余样式为。

     

字符匹配,因此下一个带有文本的递归调用:ippi和pattern   如:场景2:剩余文本为ippi,模式为p *。

     

方案2:剩余文本为ippi,模式为s p

     

方案1:文本为ippi,其余模式为p *。

     

方案1:文本为ippi,其余模式为。

     

个字符匹配,因此下一个带有文本的递归调用:ppi和pattern   :

     

方案2:剩余文字为ppi,样式为p *。

     

方案2:剩余文本为ppi,模式为s p

     

方案2:剩余文本为ssippi,模式为s p *。

最后返回False。

在此解决方案中,我无法找出是否存在任何重叠的子问题或任何我们可以重复使用的解决方案?

我什至尝试在youtube上查找。 This guy并没有告诉我们如何获得此解决方案,他只是干法运行该解决方案,因为他知道该解决方案存在问题。

我们如何确定这是否是DP问题?为此问题寻求DP解决方案的直觉是什么?

我在互联网上查询了很多东西,但仍然无法弄清重叠的子问题在哪里,以及如何解决DP问题。我也尝试为此做一棵递归树,但仍然不知道我们可以在哪里重用先前计算出的解决方案。

任何人都可以帮助我可视化重叠的子问题,还可以帮助我得出结论,如何确定这是DP问题并找到自下而上的解决方案?

1 个答案:

答案 0 :(得分:1)

这是一个测试用例,文本= {"hhT",样式= ".*h.*P"

尝试在isMatch函数调用的第一行同时打印文本和图案。您会看到文本"T"和模式".*P"出现两次。所以是的,这个问题确实存在重叠的子问题。

我努力提出一个示例的部分原因是您的代码非常优雅。我写得比较差的代码有很多重叠之处。

之所以会这样,是因为"hh"的文本可以通过两种方式使用。模式的"h"可以与文本的第一和第二"h"都匹配。但是无论哪种方式,匹配"hh"都会占用模式中的".*h",而您剩下的是"T"".*P"

因此,与斐波那契或其他经典的DP问题不同,这里不能保证子问题重叠。但这可能发生,特别是当您有很多特殊字符时。