看书做题动手!【再简单也要实践】

本文介绍了一种生成字符串所有子串的算法,包括非空子串和特定形式的子集生成方法,并提供了伪代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

  今天看书看到一个题目说的是,有一个字符串“ABCD”,设计一个算法获得其所有的子串。首先我需要澄清什么是串这个概念。

   所谓串指的是:由0个或者多个字符组成的有穷序列。

   子串:一个串中任意个连续字符组成的子序列,叫做这个串的子串。

   根据这个定义那么一个串中最大的子串就是其本身了,最小的子串就是为空。

根据定义手算的话不难得出:

  "ABCD"的非空子串是:ABCDABBCCDABCBCDABCD

分析的方法很简单,就是划线法

首先是长度为一的子串:ABCD

长度为二的子串:ABBCCD

长度为三的子串:ABCBCD

长度为四的子串:ABCD

简单分析一下可以大胆猜想求一个串的非空子串的个数的方法,如下公式:

R = 1+2+3+...+N

N:子串字符个数。

R:非空子串个数。

利用数学归纳法很容易证明。

好了,现在开始设计算法,首先把ABCD有序字符列编号为0123

那么就是要输出01230112230121230123

接下来,开始找规律,输出的各类长度的子串刚好是四个等于串的字符个数,而输出的子串随着子串中字符的增加而有规律递减,呵呵,可以设计类似如下循环:

   for i = 0 to N-1

     for j = i to 0

这样0-->0---N-1

1->0---N-2 1---N-1

… …

 i->0---N-1-i1---N-i......i---N-1

试着写写

const int nCount = strCS.GetLength();

          for ( int nIdxI = 0 ; nIdxI < nCount; ++nIdxI )

          {

               for ( int nIdxJ = nIdxI; nIdxJ >= 0; --nIdxJ )

              {

                 rgpBContainer.push_back(strCS.Mid( nIdxJ, nCount - nIdxI ));

              }

         }

  

 

     设计完了这个求非空子串的算法,我想可以展开一下,若要设计这样的算法呢:输入"ABCD",得到:ABCDABACADBCBDCDABCABDACDBCDABCD 

 

    还是很有规律的,其中有序性是一直保持的!

   试着用分治法分析一下:

    ABCD     ---- ABCD       ABCD A BCDABACDABCABDACAD B CDBCBDCD

    A<--BCD ---- A  / BCD    A BCDABACDABCABDACAD B CDBCBDCD

    B<--CD   ---- B  / CD      B CDBCBDCD

    C<--D     ----  C / D        CD

   看出规律了吧,将字符串的每个第一个字符分离出来,然后将剩余的字符继续做分离,最后分离到最后两个字符,然后将其回溯,与上次分离的第一个字符组合,最后便可以得到所有的情况了,换句话说就是之前求子串的情况加上一个首字母,也就是先将首字母分离,在求剩余字符串的子串,然后与首字母组合。

   

    到了这个地方还是自己需要跟自己强调一下,算法大致轮廓描述出来的时候,往往是最掉以轻心的时候,认为自己知道怎么去做了,于是乎就不去动手写程序来验证了,须不知,算法描述与完全实现之间是有一个鸿沟的,这个沟的深度与宽度就是随着自己想当然地似是而非地认为正确的时候越来越大越来越深,直到有一天自己跌落进去后悔莫及,打个比方快速排序这个算法应该是大家都很熟悉的,我在公司做过实验让同事写这个算法,结果就是漏洞百出,有的甚至惨不忍睹!!!,因此,知行合一这四个字的分量大家自行掂量着看了,好了不扯远了,这里我们根据这个描述试着写写它的实现:

      void GetAllBunches( CString &strCS, std::vector<CString>& rgpBunches)
       {

            const int nCount = strCS.GetLength();
            if ( nCount < 1)
                 return;
            CString strFirstLetter = strCS[0];
            strCS = strCS.Mid(1, nCount-1);
            for (int nIdI = 0; nIdI < nCount-1; ++nIdI)
           {
              for (int nIdJ = nIdI; nIdJ >= 0; --nIdJ)
              {
                   rgpBunches.push_back( strFirstLetter + strCS.Mid(nIdJ,nCount-1-nIdI) );
              }
           }

        rgpBunches.push_back( strFirstLetter );
        GetAllBunches( strCS, rgpBunches );
      }

   

OK,到这里基本上就完结了,但是如果说你需要一个实用的版本,就应该用标准c++来写,而不是依赖于MFC相关的类实现!
 

 

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值