题目:求一个字符串中最长的没有重复字符的子串。
思路:用hash表从i遍历查看包含i的最长 无重复子串。
int max_unique_substring2(char * str)
{
int i,j;
int begin;
int maxlen = 0;
int hash[256];
int n = strlen(str);
for(i=0; i<n; ++i)
{
memset(hash,0,sizeof(hash));
hash[str[i]] = 1;
for(j=i+1; j<n; ++j)
{
if(hash[str[j]] == 0)
hash[str[j]] = 1;
else
break;
}
if(j-i > maxlen)
{
maxlen = j-i;
begin = i;
}
}
printf("%.*s\n", maxlen, &str[begin]);
return maxlen;
}
动态规划:
dp[i]表示以a[i]为结尾的最长不重复子串长度,初始状态dp[0]=1; 现在判断包含str[i]元素的最长不重复子串了,
主要是判断包含str[i[元素最长子串的起始位置。如果他与他前面的最长不重复子串都没有相同的字符,那么他也可以加入这个子串中,构成一个新的子串。 最终目的还是注意每个最长子串的起始位置。
/* LNRS dp */
int dp[30];
void LNRS_dp(char * arr, int size)
{
int i, j;
int <strong>last_start </strong>= 0; // 上一次最长子串的起始位置
maxlen = maxindex = 0;
dp[0] = 1;
for(i = 1; i < size; ++i)
{
for(j = i-1; j >= last_start; --j) // 遍历到上一次最长子串起始位置
{
if(arr[j] == arr[i])
{
dp[i] = i - j;
<strong>last_start</strong> = j+1; // 更新last_start
break;
}else if(j == <strong>last_start</strong>) // 无重复
{
dp[i] = dp[i-1] + 1;
}
}
if(dp[i] > maxlen)
{
maxlen = dp[i];
maxindex = i + 1 - maxlen;
}
}
output(arr);
}
Hash
很多情况下,在描述一个字符串时,都是英文字母组成的字符,因此可能出现的元素是有限的(26个),因此就有了第二种想法,Hash。
这种想法在于使用一个大小为26的数组visited[]记录每个字符是否出现,然后枚举最长不重复子串的起点。代码如下:
void LNRS_hash(char* s)
{
char visited[26];
int i, j;
int maxlen = 0;
int maxIndex;
int len = strlen(s);
memset(visited, -1, 26);
for (i = 0; i < len; i++)
{
visited[s[i] - 'a'] = 1;
for(j = i+1 ; j < len; j++)
{
if(visited[s[j]-'a'] == -1) //该字符没有出现
{
visited[s[j]-'a'] = 1;
if(j - i+1> maxlen)
{
maxlen = j - i+1;
maxIndex = i;//最长不重复子串的起点
}
}
else
break;
}
memset(visited, -1, 26);
}
printf("%d\n", maxlen);
}