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

三种方法是一个按部就班的过程,纯纯思考这个过程对我来讲仍是有些煎熬的,虽然道理是很显然的,借助图来讲明一下,

第一种方法

第二种方法

第三种方法

相关文章
相关标签/搜索