1、最長的重復子串
尋找一個字符串中最長的重復子串
最大后綴方法思路:
1. 用字符串指針數組保存用戶輸入的字符串的所有后綴字符串;
2. 將后綴字符串集合進行排序;
3. 比較相鄰字符串的公共子串長度,找到長度最大值,保存相應字符串即為所求
空間復雜度:求長度為n的字符串的后綴,需要O(n)的空間復雜度
時間復雜度:產生后綴數組-時間復雜度O(N)、對后綴數組排序是O(N*NlogN),第一個N表示字符串的比較,后面NlogN使用快排排序。依次檢測相鄰兩個后綴的公共長度-時間復雜度O(N*N)、取出最大公共長度的前綴-時間復雜度O(N)。直接用sort排序,時間復雜度是nlog(n)。
總的時間復雜度是O(N*NlogN)
#include<iostream> #include<algorithm> #include<stdio.h> #include <vector> #include<string> #include<sstream> #include<map> #include<set> #include <functional> // std::greater using namespace std; int getCommon(string s1, string s2) { int i = 0; for (; i < s1.size()&& i<s2.size(); ++i) { if (s1[i] != s2[i]) break; } return i; } int main() { string str; cin >> str; vector<string> strs; for (int i = 0; i < str.size(); ++i) { strs.push_back(str.substr(i)); } sort(strs.begin(),strs.end()); int maxlen = 0; string res; for (int i = 1; i < strs.size(); ++i) { int len = getCommon(strs[i-1], strs[i]); if (maxlen < len) { maxlen = max(maxlen, len); res = strs[i - 1].substr(0,len); } } cout << res<<"\n" << maxlen << endl; return 0; }
2、3. 無重復字符的最長子串
給定一個字符串,找出不含有重復字符的最長子串的長度。
示例 1:
輸入: "abcabcbb"
輸出: 3
解釋: 無重復字符的最長子串是 "abc",其
長度為 3。
示例 2:
輸入: "bbbbb"
輸出: 1
解釋: 無重復字符的最長子串是 "b"
,其長度為 1。
示例 3:
輸入: "pwwkew" 輸出: 3 解釋: 無重復字符的最長子串是"wke"
,其長度為 3。 請注意,答案必須是一個子串,"pwke"
是一個子序列 而不是子串。
方法一、
我們之前手動推導的方法實際上是維護了一個滑動窗口,窗口內的都是沒有重復的字符,我們需要盡可能的擴大窗口的大小。由於窗口在不停向右滑動,所以我們只關心每個字符最后出現的位置,並建立映射。窗口的右邊界就是當前遍歷到的字符的位置,為了求出窗口的大小,我們需要一個變量left來指向滑動窗口的左邊界,這樣,如果當前遍歷到的字符從未出現過,那么直接擴大右邊界,如果之前出現過,那么就分兩種情況,在或不在滑動窗口內,如果不在滑動窗口內,那么就沒事,當前字符可以加進來,如果在的話,就需要先在滑動窗口內去掉這個已經出現過的字符了,去掉的方法並不需要將左邊界left一位一位向右遍歷查找,由於我們的HashMap已經保存了該重復字符最后出現的位置,所以直接移動left指針就可以了。我們維護一個結果res,每次用出現過的窗口大小來更新結果res,就可以得到最終結果啦。
這里我們可以建立一個256位大小的整型數組來代替HashMap,這樣做的原因是ASCII表共能表示256個字符,所以可以記錄所有字符,然后我們需要定義兩個變量res和left,其中res用來記錄最長無重復子串的長度,left指向該無重復子串左邊的起始位置,然后我們遍歷整個字符串,對於每一個遍歷到的字符,如果哈希表中該字符串對應的值為0,說明沒有遇到過該字符,則此時計算最長無重復子串,i - left +1,其中i是最長無重復子串最右邊的位置,left是最左邊的位置,還有一種情況也需要計算最長無重復子串,就是當哈希表中的值小於left,這是由於此時出現過重復的字符,left的位置更新了,如果又遇到了新的字符,就要重新計算最長無重復子串。最后每次都要在哈希表中將當前字符對應的值賦值為i+1。
class Solution { public: int lengthOfLongestSubstring(string s) { if(s.empty()) return 0; vector<int> m(256,0); int res = 0,left = 0; for(int i=0;i<s.size();++i) { left = max(left,m[s[i]]); m[s[i]] = i+1;//記錄的位置都要+1,以區別默認的0 res = max(res,i-left+1); } return res; } };
方法二:使用hash表記錄位置
class Solution { public: int lengthOfLongestSubstring(string s) { if(s.empty()) return 0; unordered_map<char,int> m; int res = 0,left = 0; // 由於map不能初始化,所以默認為0 for(int i=0;i<s.size();++i) { left = max(left,m[s[i]]); m[s[i]] = i+1; //此處記錄的是第幾個的位置 res = max(res,i-left+1);//上面加1了,此處就要-1; } return res; } };