LeetCode3. Longest Substring Without Repeating Characters

 

(0)前言算法

  原本不打算在博客裏面記錄本身刷LeetCode的通過。作了幾道題目之後發現能夠AC卻是不假,可是使用的方法在時間效率上平均只能戰勝50%左右的用戶。於是決定仍是記錄一下,不應小瞧這些基礎的題目,它們自有存在的價值。數組

(一)題意數據結構

題目連接:https://leetcode.com/problems/longest-substring-without-repeating-characters/ide

3. Longest Substring Without Repeating Characters

Given a string, find the length of the longest substring without repeating characters.優化

Examples:spa

Given "abcabcbb", the answer is "abc", which the length is 3.code

Given "bbbbb", the answer is "b", with the length of 1.blog

Given "pwwkew", the answer is "wke", with the length of 3. Note that the answer must be a substring, "pwke" is a subsequence and not a substring.leetcode

————————————————————————————————————————————————————————————————————————————字符串

(二)題解

(1)普通解法-O(n2

把全部的狀況都枚舉一遍,尋找最長不含重複字母的字串。藉助一個bool數組,快速判斷是否存在重複。代碼以下:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int len = s.length();
 5         bool vis[200];
 6         int ans = 0,sublen;
 7         for(int i = 0; i < len; i++)
 8         {
 9             memset(vis,0,sizeof vis);
10             sublen = 0;
11             for(int j = i; j < len; j++)
12             {
13                 if(!vis[s[j]])
14                 {
15                     vis[s[j]] = 1;
16                     sublen++;
17                 }
18                 else
19                 {
20                     break;
21                 }
22             
23             }
24             if(sublen > ans)    ans = sublen;
25         }
26         return ans;
27     }
28 };
LeetCode 3-1

 

(2)優化算法1-O(2n)

上面那個解法是最普通的想法。能夠解決這個問題,可是效率不高,由於每一次j都是從i逐個日後移動,而i也是逐個移動的,這致使進行了不少次重複的判斷。

而實際上在上一輪中已經作過判斷的子串能夠繼續加以利用。因而引入了set的數據結構。這種方法叫作滑動窗口法

set是集合,包含的元素相互都是不重複的。

於是只要掃一遍字符串就能夠解決問題了,可是i和j最壞狀況下會重複掃描了同一個字符,因此時間複雜度是2n。

代碼以下:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int len = s.length();
 5         set<char> sub;
 6         int i = 0, j = 0,ans = 0;
 7         //int sublen = 0;
 8         while(i < len && j < len)
 9         {
10             if(sub.find(s[j]) == sub.end())
11             {
12                 sub.insert(s[j]);
13                 j ++;
14                 if((j - i) > ans)
15                     ans = j - i;
16             }
17             else
18             {
19                 sub.erase(sub.find(s[i]));
20                 i++;
21             }
22         }
23         return ans;
24     }
25 };
LeetCode3-2

可是第一種實現用時36ms,第二種實現用時132ms。我懷疑是set的引入花費了時間。set要用O(logn)的時間查找、刪除、增長元素。

因此改爲了用hash的方法,使用bool類型的vis數組標記字符是否出現過.

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int len = s.length();
 5         int i = 0, j = 0,ans = 0;
 6         bool vis[300];
 7         memset(vis,0,sizeof vis);
 8         while(i < len && j < len)
 9         {
10             if(!vis[s[j]])
11             {
12                 vis[s[j]] = 1;
13                 j++;
14             }
15             else
16             {
17                 vis[s[i]] = 0;
18                 if(j - i > ans) 
19                     ans = j - i;
20                 i++;
21             }
22         }
23         if(j - i > ans) 
24                     ans = j - i;
25         return ans;
26     }
27 };
LeetCode3-3

 

(3)優化算法2-O(n)

是對滑動窗口的一種優化,不只記錄已經判斷過的元素,還記錄該元素對應的下標。

若是j’是與j位置相同的字符,那麼下一次i只須要從j’+1開始判斷便可,不須要重複[i+1,j']之間的這些判斷。

代碼以下:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         cout<<endl;
 5         int len = s.length();
 6         int i = 0, j = 0,ans = 0;
 7         int vis[300];
 8         for(int k = 0; k < 300; k++)
 9             vis[k] = -1;
10         while(i < len && j < len)
11         {
12             if(vis[s[j]] == -1 || vis[s[j]] < i)
13             {
14             }
15             else 
16             {
17                 if(j - i > ans) 
18                     ans = j - i;
19                 i = vis[s[j]] + 1;
20             }
21             vis[s[j]] = j;
22             j++;
23         }
24         if(j - i > ans) 
25             ans = j - i;
26         return ans;
27     }
28 };
LeetCode3-4

三種方法是一個按部就班的過程,純純思考這個過程對我來講仍是有些煎熬的,雖然道理是很顯然的,藉助圖來講明一下,

第一種方法

第二種方法

第三種方法

相關文章
相關標籤/搜索