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 };

 

转载于:https://www.cnblogs.com/wangxiaobao/p/5723804.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值