3.文字が繰り返されていない最長の部分文字列
文字列を指定して、繰り返し文字を含まない最長の部分文字列の長さを調べてください。
例1:
入力:s = "abcabcbb"
出力:3
説明:文字が繰り返されていない最長の部分文字列は "abc"であるため、その長さは3です。
例2:
入力:s = "bbbbb"
出力:1
説明:文字が繰り返されていない最長の部分文字列は "b"であるため、その長さは1です。
例3:
入力:s = "pwwkew"
出力:3
説明:文字が繰り返されていない最長の部分文字列は "wke"であるため、その長さは3です。
答えは部分文字列の長さでなければならないことに注意してください。「pwke」は部分文字列ではなく部分列です。
例4:
入力:s = ""
出力:0
提示:
0 <= s.length <= 5 * 10^4
s 由英文字母、数字、符号和空格组成
回答:
方法:スライディングウィンドウ+ハッシュテーブル
主なアイデアは、ハッシュテーブルのアイデアを使用して、部分文字列に文字が繰り返されるかどうかを判断する操作を完了することです。これにより、コードの量を大幅に減らすことができます。つまり、最初に元の配列の先頭から部分文字列を形成し、次に文字が追加されるたびに、追加された文字が元の部分文字列に表示されているかどうかを最初に判断する必要があります。それはあまりにも見ていない場合は、それがされ、この時点で存在していた場合は、プラスして続行されるスライディングウィンドウのアイデアが必要とする、スライディング私たちのストリングは、文字の繰り返しに対応する追加されたインデックスにあると、この時点で始まりますその文字に対応する添え字に1を加えたもの。次に、最初に形成された部分文字列の長さを計算します。部分文字列の開始インデックスが更新された後、カウンターとして機能するハッシュテーブルの開始インデックスの前の部分を再度更新する必要があります。その後、上記の操作を続けてください。
アイコン:
毎回新しい開始添え字の形成を容易にするために、ハッシュテーブルに格納されている値を、元の配列の文字の対応する添え字として定義することに注意してください。
詳細な表示コード:
コード:
#define max(a,b) ((a)>(b)?(a):(b))
int lengthOfLongestSubstring(char * s){
int hah[128];//哈希表
memset(hah,-1,128*sizeof(int));//先都初始化为-1
int num = 0;
int start = 0;//开始的起点
int num2 = 1;
int num3 = 0;
int x;
if(strlen(s)==0)
return 0;
if(strlen(s)==1)
return 1;
for(int i=0;i<strlen(s);i++)
{
if(hah[s[i]]==-1)//一旦还没有碰到该字符s[i]时
{
hah[s[i]]=i;//储存对应元素下标
num3++;
if(i==strlen(s)-1)//这是为了避免一直到末尾都不用更新开始下标的情况,即避免了“aab”类情况
//即可能会漏算最后形成的一个子串的长度,所以我们将这个长度与前面那些子串长度进行比较
{
x=i-start+1;
return max(x,num2);
}
}
else//一旦哈希表碰到了两次同样的字符时
{
num = i-1-start+1;//计算一下原先形成的子串长度
num2 = max(num2,num);//储存更大的子串长度
start = hah[s[i]]+1;//更新子串开始下标
for(int j=1;j<128;j++)
{
if(hah[j]<start)//将哈希表中每个字符储存的下标在新开始下标前面的部分的元素都初始化为原先的样子
{
hah[j]=-1;
}
}
hah[s[i]]=i;//原先这个没有计数,现在给他计数一下,因为他是包含在新形成的子串里的
}
}
if(num3==strlen(s))//若一直没有更新子串开始下标,即直接本身数组便是答案的情况
{
return num3;
}
else
{
return num2;
}
}