求字元最長且不重複的子串長度(暴力以及滑動視窗解決)
題目:
給定一個字串,找出不含有重複字元的最長子串的長度。
示例:
給定 "abcabcbb"
,沒有重複字元的最長子串是 "abc"
,那麼長度就是3。
給定 "bbbbb"
,最長的子串就是 "b"
,長度是1。
給定 "pwwkew"
,最長子串是 "wke"
,長度是3。請注意答案必須是一個子串,"pwke"
是 子序列 而不是子串。
暴力解決方法:
首先枚舉出所有的子串,用star記錄子串的起始點,end記錄子串的末尾。枚舉出所有的子串之後,開始檢查子串中是否存在重複的字元,若存在則該子串不符合要求,若該子串中不存在重複的字元,那麼將該子串的長度與之前的最大長度相比,若比最大長度還長,那麼更新最大長度的值。最後返回最長長度。
要點:
(1)枚舉出所有的子串 (2)要求該子串中沒有重複的字元,若存在重複的字元則不符合題目要求(3)更新不重複子串中的長度
程式碼實現(c語言)
/*更新最長長度*/ int Max(int a, int b) { int max=0; return max = a>b?a:b; } /*檢查字元ch是否存在在陣列st中*/ int contain(char *st, char ch) { int len = strlen(st); for(int i=0; i<len; i++) { if(st[i]==ch) { return 1; } } return 0; } int judge(char *s, int star, int end) { int len = strlen(s); int k = 0; char *st; st = (char *)malloc(end+1-star); /*判斷子串是否重複,需要一個數組st來儲存之前的字元,然後用當前字元與之前字元做比較,若不重複,將當前字元加入st陣列中為下次比較做準備*/ for(int i=star; i<end; i++) { if(!contain(st,s[i])) { st[k++] = s[i]; } else{ return 0; } } return 1; } int lengthOfLongestSubstring(char* s) { int len = strlen(s); int max = 0; /*枚舉出所有的子串*/ for(int i=0; i<len; i++) { for(int j=i+1; j<=len; j++) { if(judge(s,i,j))//若該子串不重複 { max = Max(max, j-i);//j-i為當前子串的長度,更新最長長度 } } } return max; }
c++實現:
class Solution { public: int Max(int a, int b) { int max = a; return max = a>b?a:b; } bool judge(string s, int star, int end) { string st=""; for(int i=star; i<end; i++) { if(st.find(s[i])==st.npos)//該元素在子串中不重複 { st.insert(st.end(),s[i]); } else{ return false; } } return true; } int lengthOfLongestSubstring(string s) { int max = 0,i=0,j=0; int len = s.size(); for(int i=0; i<len; i++) { for(int j=i+1; j<=len; j++) { if(judge(s,i,j)) { max = Max(max, j-i); } } } return max; } };
滑動視窗解決方法:
暴力解決方法,通常要反覆的檢視子串中是否有重複的字元。那麼假設從i到j-1之間的子串中沒有重複的字元了,那麼只需要堅持S[j]的元素是否與i到(j-1)中的重複。要檢查一個字元是否已經在子字串中,我們可以檢查整個子字串,這將產生一個複雜度為 O(n^2) 但是利用滑動視窗的話,可以用時間複雜度為O(1)來完成子串中的檢查。
視窗通常是在陣列/字串中由開始和結束索引定義的一系列元素的集合,即 [i,j)[i,j)(左閉,右開)。而滑動視窗是可以將兩個邊界向某一方向“滑動”的視窗。例如,我們將 [i,j)[i,j)向右滑動 11 個元素,則它將變為 [i+1,j+1)[i+1,j+1)(左閉,右開)。所以在該問題中,同時設定索引i,j 最開始兩個索引的位置是相同的,都在下標為0處。然後j開始往右滑動,滑動前要檢查,j此時所在的位置的元素是否和之前的字元重複,若不重複的話,將s[j]加入到st中,並且更新最長子串長度。若此時j所在的位置的元素和之前子串中的重複,此時j不再滑動,此時刪除st中的s[i],並且滑動i,使得st的範圍一直在i和j之間。
程式碼實現(C++)
class Solution {
public:
int Max(int a, int b)
{
int max = a;
if(b > max)
{
return b;
}
else
{
return a;
}
}
int lengthOfLongestSubstring(string s) {
int max = 0,i=0,j=0;
int len = s.size();
string st="";
while(i<len && j<len)
{
//j在子串中不重複
if(st.find(s[j])==st.npos)
{
st.insert(st.end(),s[j]);
j++;
max = Max(max, j-i);
}
else
{
st.erase(st.find(s[i]),1);
i++;
}
}
return max;
}
};