【题 目】输入一个字符串,输出该字符串中最大对称子串的长度。例如输入字符串:“google”,该字符串中最长的子字符串是“goog”,长度为4,因而输出为4。
【思 路1】一看这题就是遍历!没错,我们最直观的往往也是最容易实现的,这里我们暂且不考虑效率的问题。我们的基本思路是:我们如果有一个判断一个字符串是不是对称的函数的话,我们就可以用这个子函数逐一检查原字符串中所有的字符串,然后输出长度最大的即可。
(1)怎样判断一个字符串是不是对称的字符串?我们可以用两个指针分别指向字符串的第一个字符和最后一个字符,判断是否相等,如果不等直接返回false,如果为真则接着比较下一对字符。(2)如果遍历遍历原字符串的所有子串,首先我们让一个指针从头至尾遍历,对于这个指针的每一个字符,我们在用另一个指针逐一指向它后面的每一个字符即可。好了,两个问题都解决了,我们可以写出如下的代码:
1 #include<iostream>
2 #include<string>
3 #include<cstring>
4 using namespace std;
5
6 /************************************************
7 * 判断一个字符串是否是对称的
8 *************************************************/
9 bool IsSymmetricalString(char* pstart,char* pend)
10 {
11 if(pstart == NULL || pend == NULL || pstart > pend)
12 return false;
13
14 while(pstart < pend)
15 {
16 if(*pstart != *pend)
17 {
18 return false;
19 }
20 else
21 {
22 pstart++;
23 pend--;
24 }
25 }
26
27 return true;
28 }
29
30
31 /*************************************************
32 * 求最大对称子串的长度
33 **************************************************/
34 int MaxSymmetricalSubstringLenth(char *pstring)
35 {
36 if(pstring == NULL)
37 return 0;
38
39 int maxlength = 1;
40
41 int length = strlen(pstring);
42 char* pfirst = pstring;
43 while(pfirst < &pstring[length - 1])
44 {
45 char* psecond = pfirst + 1;
46 while(psecond <= &pstring[length - 1])
47 {
48 if(IsSymmetricalString(pfirst,psecond))
49 {
50 int templength = psecond - pfirst + 1;
51 if(templength > maxlength)
52 {
53 maxlength = templength;
54 }
55 }
56
57 psecond++;
58 }
59
60 pfirst++;
61 }
62
63 return maxlength;
64 }
65
66 int main()
67 {
68 cout<<"Please Enter Your String(the length must <1000 ):"<<endl;
69 char* yourstring = new char[1000];
70 cin>>yourstring;
71
72 cout<<"The Max Symmetrical SubString Length in Your String is:"<<endl;
73 cout<<MaxSymmetricalSubstringLenth(yourstring)<<endl;
74
75 return 0;
76 }
运行结果如下:
反思:我们现在来分析一下该算法的时间复杂度,首先遍历原字符串的所有子串有两个循环,这个时间复杂度是O(n2),我们在这两层循环之间有一个判断给定字符串是不是对称的子函数,这个子函数的时间复杂度是O(n),所以总的时间复杂度是O(n3).由于我们是由外向内判断一个字符串是不是对称的,那么对于形如aba的字子串(b可以含有很多字符),我们判断aa相等后,还得判断b是否是对称;而在判断子串b的时候还得再判断一次,换句话说有很多的子串我们是重复判断的。那么我们能不能消除这种重复呢?、
【思 路2】根据上面的分析,我们很容易想到,如果我们从内向外比较字符,那么对于aba型的字符串,如果我们判断了b是对称的,只需要再左右各移一位就可以判断下一个字符串是否是对称的,这样我们就能避免重复;然而我们需要注意的是,对于原字符串中每一个字符有两种情况,一种是子串是以单个字符为中心对称分布的,换句话说,子串的长度是奇数;另一种情况是子串以两个字符串为中心,即子串的长度是偶数。至此我们就可以写出如下的代码:
1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5 /*********************************************************************
6 * 计算字符串最大对称子串的长度
7 *********************************************************************/
8 int MaxSymmetricalSubstringLenth(char* pstring)
9 {
10 int maxlength = 1;
11
12 char* pchar = pstring + 1;
13 while(*pchar != '\0')
14 {
15 //以该字符串为中心,子串长度为奇数
16 char *pfirst = pchar - 1;
17 char *psecond = pchar + 1;
18 while(pfirst > pstring && psecond < &pstring[strlen(pstring) - 1] && *pfirst == *psecond)
19 {
20 pfirst--;
21 psecond++;
22 }
23
24 int templength = psecond - pfirst + 1;
25 if(templength > maxlength)
26 {
27 maxlength = templength;
28 }
29
30
31 //字该字符及之后的字符两个为中心,子串为偶数
32 pfirst = pchar - 1;
33 psecond = pchar;
34 while(pfirst > pstring && psecond < &pstring[strlen(pstring) - 1] && *pfirst == *psecond)
35 {
36 pfirst--;
37 psecond++;
38 }
39
40 templength = psecond - pfirst + 1;
41 if(templength > maxlength)
42 {
43 maxlength = templength;
44 }
45
46 pchar++;
47 }
48
49 return maxlength;
50 }
51
52 int main()
53 {
54 cout<<"Please Enter Your String:"<<endl;
55 char *yourstring = new char[1000];
56 cin>>yourstring;
57
58 cout<<"The Max Symmetrical SubString Length is:"<<endl;
59 cout<<MaxSymmetricalSubstringLenth(yourstring)<<endl;
60
61 delete[] yourstring;
62 return 0;
63 }
测试结果如下:
效率分析:这种算法首先需要遍历一边字符串,外层为n,对于每一个字符,需要从该字符开始有中间到两边遍历一遍,因而总的时间复杂度是O(n2).
References:
程序员面试题精选100题:http://zhedahht.blog.163.com/blog/static/25411174201063105120425/
注:
1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。
2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。