最长回文子串大小
#输入一段字符串得到最长回文字串的大小
输入:asdffdaaa
输出:4
输入:abs
输出:1
这是一种时间复杂度为O(n)的算法,它利用了字符的ASCII码,将一个保存字符的数组的每一个元素放入一个int类型的数组中,int类型数组的下标就是字符对应的ASCII码
int js(char air[])
{
int l=0,r=0; //后标和前标
int ret=0,cnt=0; //结果,次数=回文串的大小
int num[1000] = {0};
int len = strlen(air);
}
先准备需要的变量
l,r是需要移动的下标,ret是最后得到的最长子串大小,cnt是操作的次数,num是用来保存字符数组的int类型数组,将数组初始化为0,代表所有字符都为出现过,在后面的操作中如果在int数组里放入字符则int类型数组值为1。len计算字符数组的大小。
#以absb为例子(num等号左边为下标,右边为值)
开始时以a为回文子串的头
下标 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | b | a | c |
前标 | r=0 | |||
后标 | l=0 | |||
num | 97 = 0 | 98 = 0 | 97 = 0 | 99 = 0 |
ret = 0;ctn = 0
- 进行第一轮循环时
下标 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | b | a | c |
前标 | r=1 | |||
后标 | l=0 | |||
num | 97 = 1 | 98 = 0 | 97 = 0 | 99 = 0 |
ret = 1,cnt = 1
- 进行第二轮循环时
下标 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | b | a | c |
前标 | r=2 | |||
后标 | l=0 | |||
num | 97 = 1 | 98 = 1 | 97 = 0 | 99 = 0 |
ret = 2,cnt = 2
- 进行第三轮循环时
下标 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | b | a | c |
前标 | r=3 | |||
后标 | l=0 | |||
num | 97 = 1 | 98 = 1 | 97 = 1 | 99 = 0 |
此时发现下标为97时都为1,那么判断出aba是一个回文串,接下来让num[97] = 0,表示已经找到一组,然后重新开始查找。
移动后标,使用后标加1,cnt次数减一(表示除去a是回文串的情况)
下标 | 0 | 1 | 2 | 3 |
---|---|---|---|---|
字符 | a | b | a | c |
前标 | r=3 | |||
后标 | l=1 | |||
num | 97 = 0 | 98 = 1 | 97 = 0 | 99 = 0 |
ret = 2,cnt = 1
此时b为回文子串的头,num[97] = 0,符合使r++的情况,但是已经到达循环结束条件,此时循环结束。
简单来说就是暴力枚举每一个字符,以每个字符为头,然后找出以它为头的回文字符串。然后巧妙利用结果和次数的关系找到最大的
完整代码如下:
#include <stdio.h>
#include <string.h>
int js(char air[]);
int main()
{
int n;
char air[1000000];
scanf("%s",air);
printf("%d",js(air));
return 0;
}
int js(char air[])
{
int l=0,r=0; //左标和右标
int ret=0,cnt=0; //结果,次数
int num[1000] = {0};
int len = strlen(air);
while(r<len) //循环进行的条件
{
if(num[air[r]] == 0) //如果字符为出现过则进入循环
{
num[air[r]] = 1; //出现过的字符被标记为1
r++; //移动前标的值
cnt++; //进行的次数加1,次数就是回文串的大小
/* 保存最大结果,使cnt不断变化得到新的值 */
if(ret>cnt) //使ret始终比cnt大
{
ret = ret;
}
else{
ret = cnt;
}
}
else{
num[air[l]] = 0; //如果字符已经出现让字符重新归零,然后重新寻找
l++; //移动后标的值
cnt--; //让进行的次数减一
}
}
}