看书做题动手!【再简单也要实践】
2008-03-24 22:12
225 查看
今天看书看到一个题目说的是,有一个字符串“ABCD”,设计一个算法获得其所有的子串。首先我需要澄清什么是串这个概念。
所谓串指的是:由0个或者多个字符组成的有穷序列。
子串:一个串中任意个连续字符组成的子序列,叫做这个串的子串。
根据这个定义那么一个串中最大的子串就是其本身了,最小的子串就是为空。
根据定义手算的话不难得出:
"ABCD"的非空子串是:A、B、C、D、AB、BC、CD、ABC、BCD、ABCD
分析的方法很简单,就是“划线法”:
首先是长度为一的子串:A、B、C、D。
长度为二的子串:AB、BC、CD
长度为三的子串:ABC、BCD
长度为四的子串:ABCD
简单分析一下可以大胆猜想求一个串的非空子串的个数的方法,如下公式:
R = 1+2+3+...+N
N:子串字符个数。
R:非空子串个数。
利用数学归纳法很容易证明。
好了,现在开始设计算法,首先把ABCD有序字符列编号为0123
那么就是要输出0、1、2、3、01、12、23、012、123、0123
接下来,开始找规律,输出的各类长度的子串刚好是四个等于串的字符个数,而输出的子串随着子串中字符的增加而有规律递减,呵呵,可以设计类似如下循环:
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-i、1---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",得到:A、B、C、D、AB、AC、AD、BC、BD、CD、ABC、ABD、ACD、BCD、ABCD 。
还是很有规律的,其中有序性是一直保持的!
试着用分治法分析一下:
ABCD ---- ABCD : ABCD、 A、 BCD、AB、ACD、ABC、ABD、AC、AD、 B、 CD、BC、BD、C、D
A<--BCD ---- A / BCD : A、 BCD、AB、ACD、ABC、ABD、AC、AD、 B、 CD、BC、BD、C、D
B<--CD ---- B / CD : B、 CD、BC、BD、C、D
C<--D ---- C / D : C、D
看出规律了吧,将字符串的每个第一个字符分离出来,然后将剩余的字符继续做分离,最后分离到最后两个字符,然后将其回溯,与上次分离的第一个字符组合,最后便可以得到所有的情况了,换句话说就是之前求子串的情况加上一个首字母,也就是先将首字母分离,在求剩余字符串的子串,然后与首字母组合。
到了这个地方还是自己需要跟自己强调一下,算法大致轮廓描述出来的时候,往往是最“掉以轻心”的时候,认为自己知道怎么去做了,于是乎就不去动手写程序来验证了,须不知,算法描述与完全实现之间是有一个“鸿沟”的,这个沟的深度与宽度就是随着自己想当然地似是而非地认为正确的时候越来越大越来越深,直到有一天自己跌落进去后悔莫及,打个比方快速排序这个算法应该是大家都很熟悉的,我在公司做过实验让同事写这个算法,结果就是漏洞百出,有的甚至惨不忍睹!!!,因此,知行合一这四个字的分量大家自行掂量着看了,好了不扯远了,这里我们根据这个描述试着写写它的实现:
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相关的类实现!
所谓串指的是:由0个或者多个字符组成的有穷序列。
子串:一个串中任意个连续字符组成的子序列,叫做这个串的子串。
根据这个定义那么一个串中最大的子串就是其本身了,最小的子串就是为空。
根据定义手算的话不难得出:
"ABCD"的非空子串是:A、B、C、D、AB、BC、CD、ABC、BCD、ABCD
分析的方法很简单,就是“划线法”:
首先是长度为一的子串:A、B、C、D。
长度为二的子串:AB、BC、CD
长度为三的子串:ABC、BCD
长度为四的子串:ABCD
简单分析一下可以大胆猜想求一个串的非空子串的个数的方法,如下公式:
R = 1+2+3+...+N
N:子串字符个数。
R:非空子串个数。
利用数学归纳法很容易证明。
好了,现在开始设计算法,首先把ABCD有序字符列编号为0123
那么就是要输出0、1、2、3、01、12、23、012、123、0123
接下来,开始找规律,输出的各类长度的子串刚好是四个等于串的字符个数,而输出的子串随着子串中字符的增加而有规律递减,呵呵,可以设计类似如下循环:
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-i、1---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",得到:A、B、C、D、AB、AC、AD、BC、BD、CD、ABC、ABD、ACD、BCD、ABCD 。
还是很有规律的,其中有序性是一直保持的!
试着用分治法分析一下:
ABCD ---- ABCD : ABCD、 A、 BCD、AB、ACD、ABC、ABD、AC、AD、 B、 CD、BC、BD、C、D
A<--BCD ---- A / BCD : A、 BCD、AB、ACD、ABC、ABD、AC、AD、 B、 CD、BC、BD、C、D
B<--CD ---- B / CD : B、 CD、BC、BD、C、D
C<--D ---- C / D : C、D
看出规律了吧,将字符串的每个第一个字符分离出来,然后将剩余的字符继续做分离,最后分离到最后两个字符,然后将其回溯,与上次分离的第一个字符组合,最后便可以得到所有的情况了,换句话说就是之前求子串的情况加上一个首字母,也就是先将首字母分离,在求剩余字符串的子串,然后与首字母组合。
到了这个地方还是自己需要跟自己强调一下,算法大致轮廓描述出来的时候,往往是最“掉以轻心”的时候,认为自己知道怎么去做了,于是乎就不去动手写程序来验证了,须不知,算法描述与完全实现之间是有一个“鸿沟”的,这个沟的深度与宽度就是随着自己想当然地似是而非地认为正确的时候越来越大越来越深,直到有一天自己跌落进去后悔莫及,打个比方快速排序这个算法应该是大家都很熟悉的,我在公司做过实验让同事写这个算法,结果就是漏洞百出,有的甚至惨不忍睹!!!,因此,知行合一这四个字的分量大家自行掂量着看了,好了不扯远了,这里我们根据这个描述试着写写它的实现:
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相关的类实现!
相关文章推荐
- 【Unix/Linux编程实践】 动手实现简单的more
- 【学习笔记+实践】简单的导航条菜单制作
- 自己动手,丰衣足食——一个简单却高效的图像旋转算法
- ELK 作为交换机和路由器日志管理系统的简单实践!
- 收藏的SQL知识以及SQL语句简单实践通俗易懂
- KMP算法实践与简单分析
- 单片机的动手实践篇--51单片机玩转12864
- 简单的2D射击游戏实践
- 自己做题的简单的算法
- ViewModel 实践:高效简单地组织代码
- 【原创 Hadoop&Spark 动手实践 13】Spark综合案例:简易电影推荐系统
- 史上最简单Robotium跨进程操作实践——基于ADB框架
- Angular2 Service实践——实现简单音乐播放服务
- Python编程:从入门到实践的动手试一试(第五章)
- 自己动手写最简单的Android驱动---LED驱动的编写
- DataStage实践之简单入门
- Python编程:从入门到实践的动手试一试答案(第十一章)
- 自己使用window.open和window.showModalDialog在父子窗口传值的实践简单总结
- 也说Autofac在MVC的简单实践:破解在Controller构造函数中的实例化 - winhu
- MongoDB简单实践:Only CRUD