第二章、动态规划算法(2.4.1-2.4.2.3)------匹配问题

目录
2.4动态规划算法实现------匹配问题
2.4.1通配符匹配问题
2.4.1.1问题
2.4.1.2确定动态规则(DP、状态转移方程)、初始值
(1)直接相关状态
(2)当前状态值的确定
(3)动态规则(DP、状态转移方程)
(4)初始值
2.4.1.3动态规划算法代码实现
(1)完整代码
(2)程序速度优化
2.4.2正则表达式匹配问题
2.4.2.1问题
2.4.2.2确定动态规则(DP、状态转移方程)、初始值
(1)直接相关状态
(2)子状态空间与子状态
(3)当前状态值的确定
(4)动态规则(DP、状态转移方程)
(5)初始值
2.4.2.3动态规划算法代码实现
(1)完整代码
(2)程序速度优化

2.4动态规划算法实现------匹配问题

2.4.1通配符匹配问题

2.4.1.1问题

       通配符匹配(Wildcard Matching),对于给定的两个字符串A和B,判断B字符串是否匹配A字符串,其中,B中可以含有?或*通配符,此时,B中的?可以匹配单个字符(不含空字符),*可以匹配任意长度字符串(可以是空字符、单个字符、多个字符序列)。

       在计算机中讲到单个字符,一般不包括空字符,特别是在匹配的语境中,显然,空字符没必要作为匹配对象。计算机中的通配符(wildcard,也翻译为wildcard characters)一般表示代替一个或多个字符。计算机中通配符表示在匹配时这种字符脱离本义(原义),代表某种作用。

      本题实际也是字符串匹配问题,类似正则表达式匹配问题,但本题中是通配符(wildcard, wildcard characters)的匹配,这种匹配需要A与B完全对应到才算匹配成功,而编程语言内置函数的正则表达式匹配成功,只需要正则表达式B在A字符串中能匹配到即可,也即B匹配到的可以是A的局部。

2.4.1.2确定动态规则(DP、状态转移方程)、初始值

(1)直接相关状态

        Python的切片是左闭右开的,因而,A[0:i]不包含A[i]、B[0:j]不包含B[j],下面阅读时注意这一点。

        A[0:i]表示字符串A的前i个字符构成的局部字符串,B[0:j] 表示字符串B的前j个字符构成的局部字符串。在计算过程中i,j是随着循环而取值的,我们可以记dp[i][j]是A[0:i]被B[0:j]匹配的结果,若匹配成功,则dp[i][j]为True,否则,为False。i,j取到当A[0:i]、B[0:j]分别代表各自整个字符串时,就是最终状态,这也是我们要所求的问题。

扫描二维码关注公众号,回复: 17208185 查看本文章

       在题目中B中的?或*具有题目中描述的匹配功能,而被匹配字符串A中若有?或*,只看作是字符,就是字面的含义。而且,B中的?或*只对A中的字符进行匹配,不对自身B中其前面的字符由影响。在正则表达式中*会对其前面的字符有影响。在本题中,给定B、A后,B、A不会有变化,在当前状态匹配时对应字符串的长度也是固定的,B中的*可以匹配A中的多个字符。因此,在每个状态中,给定B、A后不用考虑B的变化,但在后面讲到的正则表达式匹配中要考虑B的变化。

       在匹配中,一般来讲,若两个字符串中各个位置的字符能对应一致(相等),则匹配成功,但由于本例中?或*具有特殊的匹配含义,因此, 在匹配时,实际是判断对应位置的单个字符是否相等,当不相等时,应该考虑B中对应位置是否存在?或*(因为在不相等时它们也可以匹配)。

       在循环中,两个字符串的字符逐个进行匹配时,匹配的实现方式就是首先判断B[j-1]是否与A[i-1]相等,若不相等,还可以通过B[j-1]=’?’或B[j-1]=’*’来实现匹配,这三种方式都没实现匹配,则B不能匹配A。

        本例与前面讲的空间中的移动(路径)问题、转换(编辑)问题是有一定差异的,前面讲的这些问题都是问题的主体发生改变逐渐演变出一个结果。本例是事先给定A、B,然后是它们之间逐个字符进行匹配,最后判断这两个字符串是否匹配成功。在本题中,是通过匹配来实现状态转移,当前状态是由相邻状态转移而来,但在匹配中,当前状态值为真(也即匹配成功)时,而这个相邻状态不一定为真,因为字符串长度发生了变化可能影响到是否匹配成功,因而,我们的重点是需要找出当前状态为True时应该由什么相邻状态决定。显然,我们是要确保匹配成功时值为True,不应该出现匹配成功时动态规划算法得出是False,因而我们重点是关注dp[i][j]值为True是由哪些直接相关状态决定的,至于False不是重点,因为确定了True的情形,反之就是False了。

       显然,匹配到当前状态dp[i][j]值是与相邻状态dp[i-1][j-1]、dp[i][j-1]、dp[i-1][j]有关的,因为相邻状态的下一步就是达到当前状态,上一步的匹配值与当前位置字符的匹配结果就决定了当前状态dp[i][j]值。因此,dp[i][j]的直接相关状态就是dp[i-1][j-1]、dp[i][j-1]、dp[i-1][j]。下面我们根据状态转移的匹配因素来讨论dp[i][j]与直接相关状态dp[i-1][j-1]、dp[i][j-1]、dp[i-1][j]的关系。

(2)当前状态值的确定

       下面讨论在不同情形下的状态转移,当前状态ij的状态值dp[i][j]为True是如何确定的,至于False不是重点,因为确定了True的情形,反之就是False了。

当B[j-1]等于A[i-1]时的状态转移

       B[j-1]是字符串B[0:j]的末尾字符,A[i-1]是字符串A[0:i]的末尾字符,由于B[j-1]等于A[i-1], B[0:j]与A[0:i]的最后一个字符能对应匹配,因而B[0:j]能否匹配A[0:i],由B[0:j-1]与A[0:i-1]的匹配结果决定,因而,当前状态值dp[i][j]由dp[i-1][j-1]决定了,即dp[i][j]= dp[i-1][j-1]。

当B[j-1]不等于A[i-1]时的状态转移

       考虑到?与*的通配符功能,要做如下区分。

       如果B[j-1]等于’?’,由于?可以匹配单个空字符(不含空字符),显然,B[0:j]与A[0:i]的最后一个字符能对应匹配,因而B[0:j]能否匹配A[0:i],由B[0:j-1]与A[0:i-1]的匹配结果决定,因而,当前状态值dp[i][j]由dp[i-1][j-1]决定了,即dp[i][j]= dp[i-1][j-1]。

       如果B[j-1]等于’*’,考虑到*可以匹配任意长度字符串,可以是空字符、单个字符、多个字符序列,因此,此时的dp[i][j]值由相邻的dp[i-1][j-1]、dp[i][j-1]、dp[i-1][j]任意一个确定,即dp[i][j]= dp[i][j-1]| dp[i-1][j]| dp[i-1][j-1],具体分析如下。

       由状态dp[i][j-1]到状态dp[i][j],若相邻状态dp[i][j-1]值为True,说明B[0:j-1]与A[0:i]能匹配,而*能匹配空字符,显然B增加一个’*’也能有B[0:j]匹配A[0:i],即dp[i][j]= dp[i][j-1];

       由状态dp[i-1][j]到状态dp[i][j],若相邻状态dp[i-1][j] 值为True,说明B[0:j]与A[0:i-1]能匹配,而*能匹配多个字符,因而B[0:j]与A[0:i]能匹配,即dp[i][j]= dp[i-1][j];

       由状态dp[i-1][j-1]到状态dp[i][j],若相邻状态dp[i-1][j-1] 值为True,说明B[0:j-1]与A[0:i-1]能匹配成功,而B[j]等于’*’, 因而B[0:j]与A[0:i]能匹配,即dp[i][j]= dp[i-1][j-1];

       因此,当B[j-1]等于’*’,有dp[i][j]= dp[i][j-1]| dp[i-1][j]| dp[i-1][j-1]。

      另外,此时由于B[j-1]等于’*’,也必然有B[0:j]与A[0:i-1]能匹配成功,也即当dp[i-1][j-1] 值为True,必然有dp[i-1][j] 值为True,因此,这个dp[i][j]= dp[i][j-1]| dp[i-1][j]| dp[i-1][j-1]可以简化为dp[i][j]= dp[i][j-1]| dp[i-1][j],也就是讲,这两个等式右边的值是一样的,因为当dp[i-1][j-1]=True,必然有dp[i-1][j] =True,因而由dp[i][j]= dp[i][j-1]| dp[i-1][j]|True可得dp[i][j]= dp[i][j-1]| dp[i-1][j],当dp[i-1][j-1]=False时,dp[i][j]= dp[i][j-1]| dp[i-1][j]|False,也即dp[i][j]= dp[i][j-1]| dp[i-1][j],其中|表示或,要注意逻辑运算符或的作用,当然,使用dp[i][j]= dp[i][j-1]| dp[i-1][j]| dp[i-1][j-1]更能表现相邻状态的影响。

        如果B[j-1]不等于’?’和’*’,由B[j-1]不等于A[i-1]可知,B[0:j]与A[0:i]的最后一个字符不能对应匹配,显然,,B[0:j]与A[0:i]不能匹配,因而dp[i][j]=False。

猜你喜欢

转载自blog.csdn.net/thefg/article/details/134628150