python查找字符串出现次数_查找字符串中子序列的出现次数

这是一个经典的dynamic programming问题(通常不使用正则表达式解决)。My naive implementation (count the 3's for each 2 after each 1) has been running for an hour and it's not done.

这将是一个在指数时间内运行的穷举搜索方法。(不过,我很惊讶它能持续几个小时)。

下面是一个动态编程解决方案的建议:

递归解决方案的大纲:

(很抱歉描述太长了,但每一步都很简单,请耐心等待;-)如果子序列为空,则会找到匹配项(没有数字可供匹配!)我们返回1

如果输入序列为空,则表示我们的位数已耗尽,无法找到匹配项,因此返回0

(序列和子序列都不是空的。)

(假设“abcdef”表示输入序列,“xyz”表示子序列。

将result设置为0

在result中添加bcdef和xyz的匹配数(即放弃第一个输入数字并递归)

如果前两个数字匹配,即a=x在result中添加bcdef和yz的匹配数(即匹配第一个子序列数字并在其余子序列数字上递归)

返回result

示例

下面是对输入1221/12的递归调用的说明。(子序列为粗体,·表示空字符串。)

xtiRG.png

动态规划

如果简单地实现,一些(子)问题会被多次解决(例如上图中的·/2)。动态编程通过记住以前解决的子问题(通常在查找表中)的结果来避免这种冗余计算。

在这种情况下,我们用[序列长度+1]行,以及

[子序列长度+1]列:

8MXJc.png

我们的想法是在相应的行/列中填写221/2的匹配数。一旦完成,我们应该在1221号细胞中找到最终的解决方案。

我们开始用我们立即知道的内容填充表(“基本情况”):当没有留下子序列数字时,我们有1个完全匹配:

YDJhP.png如果没有序列号,则不能有任何匹配项:

QXruq.png

然后,我们按照以下规则从上到下/从左到右填充表:在单元格[行][列]中,写入在[行-1][col]中找到的值。

直观地说,这意味着221/2的匹配数包括21/2的所有匹配

如果行行处的序列和列列处的subseq以相同的数字开始,则将在[行-1][列-1]处找到的值添加到刚刚写入的值[行[列]。

直观地说,这意味着“1221/12的匹配数也包括221/12的所有匹配数”

l71gT.png

最终结果如下:

qxDvE.png

右下角单元格的值确实是2。

在代码中

不是用Python写的,(我道歉)。class SubseqCounter {

String seq, subseq;

int[][] tbl;

public SubseqCounter(String seq, String subseq) {

this.seq = seq;

this.subseq = subseq;

}

public int countMatches() {

tbl = new int[seq.length() + 1][subseq.length() + 1];

for (int row = 0; row < tbl.length; row++)

for (int col = 0; col < tbl[row].length; col++)

tbl[row][col] = countMatchesFor(row, col);

return tbl[seq.length()][subseq.length()];

}

private int countMatchesFor(int seqDigitsLeft, int subseqDigitsLeft) {

if (subseqDigitsLeft == 0)

return 1;

if (seqDigitsLeft == 0)

return 0;

char currSeqDigit = seq.charAt(seq.length()-seqDigitsLeft);

char currSubseqDigit = subseq.charAt(subseq.length()-subseqDigitsLeft);

int result = 0;

if (currSeqDigit == currSubseqDigit)

result += tbl[seqDigitsLeft - 1][subseqDigitsLeft - 1];

result += tbl[seqDigitsLeft - 1][subseqDigitsLeft];

return result;

}

}

复杂性

这种“填表”方法的一个好处是,计算复杂度是微不足道的。每一个单元的工作量是恒定的,我们有序列行的长度和子序列的长度柱。复杂度为O(M N),其中M和N表示序列的长度。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值