LeetCode3 Longest Substring Without Repeating Characters

题意:

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

Examples:

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

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

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. (Medium)

 

解法1

自己开始AC的想法,用两重循环,搜索以s[i]开头的字串中的最长无重字串,所以一旦有重复元素出现(利用letters判重),内层的循环就可以直接跳出;

复杂度不会超过O(256(n)),因为内层最对走256步必有重复,可以不再走下去。 时间跑出来是60ms

代码1:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int result = 0;
 5         int letters[256] = {0};
 6         int tempResult;
 7         for (int i = 0; i < s.size(); ++i) {
 8             if (i + result >= s.size()) {
 9                 break;
10             }
11             tempResult = 1;
12             memset(letters, 0 , sizeof(letters));
13             letters[s[i]] = 1;
14             for (int j = i + 1; j < s.size(); ++j) {
15                 if (letters[s[j]] == 0) {
16                     tempResult++;
17                     letters[s[j]] = 1;
18                 }
19                 else {
20                     break;
21                 }
22             }
23             result = max(result, tempResult);
24         }
25         return result;
26     }
27 };

解法2

滑动窗口方法

用left记录当前考察的可行字串的最左端,i循环遍历整个字串。

如果遇到不重复元素,则添加进hash表内,并更新最大值;

如果遇到重复元素,将left开始递增,直至跳过重复元素,然后同上操作,将该元素添加进hash表,并更新最大值。

代码2利用unodered_set实现(估计find方法效率又低了,只有72ms), 代码3利用单独开的数组实现,效率更高(16ms)。

盗用网上一幅图,出处不详...

 

复杂度O(2n) = O(n) ;   left,i各自遍历一遍O(2n)

代码2:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         unordered_set<char> hash;
 5         int left = 0;
 6         int result = 0;
 7         for (int i = 0; i < s.size(); ++i) {
 8             if (hash.find(s[i]) != hash.end()) {
 9                 while (s[left] != s[i]) {
10                     hash.erase(s[left]);
11                     left ++;
12                 }
13                 hash.erase(s[left]);
14                 left ++;
15             }
16             hash.insert(s[i]);
17             result = max(result, i - left + 1);
18         }
19         return result;
20     }
21 };

代码3:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int letters[256] = {0};
 5         int left = 0;
 6         int result = 0;
 7         for (int i = 0; i < s.size(); ++i) {
 8             if (letters[s[i]] != 0) {
 9                 while (s[left] != s[i]) {
10                     letters[s[left]] = 0;
11                     left ++;
12                 }
13                 letters[s[left]] = 0;
14                 left ++;
15             }
16             letters[s[i]] = 1;
17             result = max(result, i - left + 1);
18         }
19         return result;
20     }
21 };

 

 解法3

解法3是在2的基础上的一个简单优化, letters数组只用来保存存在与否有些浪费,同时用while循环递增left找到重复元素出现位置下一位效率略低;

可以将letters数组改为存储某个字符最近出现的位置lastIndex[256],这样更新left时,直接将left = lestIndex[s[i]] + 1即可, 将 O(2n)变为真正的一次循环 O(n)

代码4:

 1 class Solution {
 2 public:
 3     int lengthOfLongestSubstring(string s) {
 4         int lastIndex[256]; // 上次出现该字符的下标
 5         int left = 0;           //当前维护的字串的最左端
 6         int result = 0;
 7         memset(lastIndex, -1, sizeof(lastIndex));
 8         for (int i = 0; i < s.size(); ++i) {
 9             if (lastIndex[s[i]] >= left) { //在这个字串内有重复 >= left
10                 left = lastIndex[s[i]] + 1;
11             }
12             lastIndex[s[i]] = i;
13             result = max(result, i - left + 1);
14         }
15         return result;
16     }
17 };

 

posted @ 2016-07-31 20:15  wangxiaobao1114  阅读(173)  评论(0编辑  收藏  举报