实现substr字符串函数,使其从给定字符串中找到最长的连续子串,该字串中任何两个字符都不相同,返回符合要求的最长子串的长度即可。
示例1
输入:
abcdeafghcijkl
输出:
11
示例2
输入:
dccfghopqmnf
输出:
9
首先如何判断一个子串中的任何两个字符都不相同?
以以array[5] = “abca”为例(为什么是5?因为要给字符串最后的”\0”保留一个位置),定义两个下标start和i,start指向我们要找的子串的第一个字符,i指向给定字符串的某个字符,start和i之间为一个子串,该子串中任何两个字符都互不相同;
1、start和i都指向0;很明显此时符合要求的最长子串的长度是1;
2、仍然将start指向0,i指向1;此时只需要判断array[0 : 1]和array[1]这个元素是否都不相同,则本例中符合要求的最长子串的长度是2;
3、仍然将start指向0,i指向2;此时只需要判断array[0 : 2]和array[2]这个元素是否都不相同,如果array[0 : 2]都和array[2]不同,则start和i之间的子串就是任何两个字符都不相同的子串。则本例中符合要求的最长子串的长度是3;(这儿注意,我们通过第1、2步已经保证了array[0 : 1] 和array[1]之间的互不相同)
4、start指向0,i指向3;此时只需要判断array[0 : 3]和array[3]这个元素是否都不相同,array[0] == array[3] 成立,此时将start往后移动一个单位,即start = 1,判断array[1:3]是否和array[3]都不相同,如果都不相同的话,array[1:3]、array[3]这个子串中任意两个元素都是互不相同的。所以此时还需要判断这个子串和第3步中求得的子串的长度谁大谁小,因为题目要求我们输出符合要求的最长子串的长度。
注:array[x : y]代表 array[x], array[x+1], ~~~ ,array[y-1];
ps:算法的逻辑真的是很难用文字来清晰的表达,我有限的语言暂时只能表达成这个样子了
对应于上面的思想的算法如下(C语言):
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#define true 1
#define false 0
int substr(char *input)
{
int output = 0; //返回值;
int len = strlen(input);
int count = 0; //start和i之间的计数;
int start = 0;
int isOk = true;
int long LastIndex = 0;
//int output = 0;
for(int i = 0; i < len; i++){
isOk = true;
for (int j = 0; j < count; j++) {
if (input[j + start] == input[i]) {
isOk = false;
start = j + start + 1;
break;
}
}
if (isOk) {
count++;
if (i == len - 1 && output < count)
output = count;
}
else {
if (output < count)
output = count;
count = i - start + 1;
}
}
return output;
}
int main(void)
{
char input[1024 + 1];
int output;
scanf("%s", input);
output = substr(input);
printf("%d\n", output);
return 0;
}
【方法2】
如果说我们的条件没有那么苛刻,即假如给定的字符串中只包含小写字母的话,那么这个题目还可以这么做:
//假设 给定的字符串中只包含小写字母;
#include <iostream>
#include <memory.h>
using namespace std;
char flag[26];
string str;
bool judge(int left, int right){
memset(flag, 0, sizeof(flag));
int i = 0;
for(i = left; i <= right; i++){
if(flag[str[i] - 'a'] == 0)
flag[str[i] - 'a']++;
else
break;
}
if(i == right+1)
return true;
else
return false;
}
int main()
{
while(cin >> str){
int len = str.size();
if(len > 26)
len = 26;
int i = 0, j = 0;
for( i = len-1; i >0; i--){
for( j = 0; j + i < str.size(); j++){
if(judge(j, j+i)){
cout << i+1 << endl; //进入这个if判断条件,这个str对应的最长不重复子串的长度就找到了。
break;
}
}
if( j+i != str.size()){//这儿之所以做这么麻烦,是为了实现上面的多个用例连续的测试功能。
break;
}
}
}
return 0;
}
judge函数的功能是判断一段连续的子串是否为全部相同的字母,
程序的总体思想,将给定的字符串 按照滑动窗口的方式来判断窗口内的字符串时候满足互相不相同这个条件,滑动串口的大小从大到小递减尝试,因为我们要求的是最长的长度。而且滑动窗口最长也就是26,因为一共就只有26个字母。
在上面的示例代码中,i控制的是窗口的大小,j来控制在窗口大小为i的情况下的移动,当judge(j, j+i)返回为真时,这就代表我们找到了最长的不重复子串的长度,即为:(j + i) - (j)+ 1 = i+1