蛙蛙推荐:[算法练习]最长不完全匹配子串频率计算

算法描述:找出一个长字符串里的某个特定的子串出现的频率,匹配的子串的上一个字符和下一个字符不需要紧紧相邻,只要满足下一个字符在当前字符的后面就行。
算法要求:长字符串的宽度最长是500个字符。
输入:一个长字符串,宽度不能超过500个字符,一个短字符串
输出:短字符串在长字符串中出现的次数的后四位,不足四位左边填充零。

举例来说:在“wweell”字符串中找“wel”出现的次数,可以匹配到8次,应输出0008,每个匹配子串的索引序列分别如下
0,2,4
0,2,5
0,3,4
0,3,5
1,2,4
1,2,5
1,3,4
1,3,5

算法分析:能够想到的最直观的做法就是先在长串里找出短串的第一个字符所在的索引,组成一个首字符索引数组,然后分别处理每个首字符索引到长串末尾的子串。处理每个子串最蛮力的办法当然是递归,递归有几点要说明。
1、递归的每次必须要有前进的趋势,所以每次递归操作,要把当前扫描的长串的索引加一,以便下面的递归使用不同的上下文。
2、递归必须有明确的终止,当短串匹配完毕,应该是到达递归的最底层了,要递增一次匹配次数,并且return,为了调试方便,我们还打印出来了匹配短串在长串中的索引序列。
3、为了尽可能多的匹配结果,在我们匹配到一个字符的时候,除了把匹配字符加一,扫描索引加一继续递归外,我们还要进行一次匹配字符不加一,扫描索引加一继续递归。
4、当扫描到字串的最后一个字符时,一次匹配已经产生了,但你还要看看长串有没有扫描完,然后继续递归匹配子串的最后一个字符,以找到更多的匹配。

以上思路的实现代码很短,如下

internal   class  Program2 {
    
private   static   string  math  =   " welcome to cnblogs " ;
    
private   static   readonly   string [] arr  =   new   string [math.Length];
    
private   static   int  ret;
    
private   static   string  test_input  =   " wweellccoommee to cnblogs " ;

    
private   static   void  Main() {
        ret 
=   0 ;
        var windex 
=   new  List < int > ();
        
for  ( int  i  =   0 ; i  <  test_input.Length; i ++ ) {
            
if  (test_input[i]  ==   ' w ' )
                windex.Add(i);
        }
        windex.ForEach(index 
=>  {
            arr[
0 =  index.ToString();
            Handle(
1 , index  +   1 );
        });

        
string  strRet  =  ret.ToString();
        
if  (strRet.Length  >   4 )
            strRet 
=  strRet.Substring(strRet.Length  -   4 4 );
        
if  (strRet.Length  <   4 ) strRet  =  strRet.PadLeft( 4 ' 0 ' );

        Console.WriteLine(strRet);
        Console.ReadKey();
    }

    
private   static   void  Handle( int  k,  int  start) {
        
for  ( int  i  =  start; i  <  test_input.Length; i ++ ) {
            
if  (k  ==  math.Length  -   1   &&  test_input[i]  ==  math[k]) {
                arr[k] 
=  i.ToString();
                Console.WriteLine(
string .Join( " , " , arr));
                
                
++ ret;
                
if  (i  <  test_input.Length  -   1 )
                    Handle(k, 
++ i);
                
return ;
            }
            
if  (test_input[i]  ==  math[k]) {
                arr[k] 
=  i.ToString();

                Handle(
++ k, i);
                Handle(
-- k,  ++ i);
                
-- i;
                
break ;
            }
        }
    }
}
但效率不高,要是处理的长串是“wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwweeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeellllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllcccccccccccccccccccccccccccccccccccccccccccccccccccccooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooommmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee to cnblogs”,不知道嘛时候才能算完,而且算出来的ret可能会溢出,呵呵。
大家有什么好的思路,给表演一把,另外这个是code jam 2009的一个入围题目,大家有兴趣可以去玩玩。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值