5/2 LeetCode每日一题 3. 无重复字符的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1: 输入: “abcabcbb” 输出: 3 解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。 示例 2:
输入: “bbbbb” 输出: 1 解释: 因为无重复字符的最长子串是 “b”,所以其长度为 1。 示例 3: 输入:
“pwwkew” 输出: 3 解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。 请注意,你的答案必须是 子串
的长度,“pwke” 是一个子序列,不是子串。
每天同步在公众号 算法学习笔记 中更新,欢迎各位关注!
分析:
这是一道非常经典的双指针法中的滑动窗口问题。
解法1:暴力法
首先很容易想到暴力法:设置首尾两个指针 i , j :
for (i in s) for (j in s[i:]) for (k in s[i:j]) for (l in s[k:j]) if (s[k] == s[l]) len=1; else len++; res = max(len,res);
时间复杂度。。。爆炸了;空间复杂度 O(1)
那么稍微聪明点的做法就是把有无重复元素判断封装起来,用桶或者哈希表之类的方式实现。
for (i in s) for (j in s[i:]) if (s[i:j]中无重复元素) res = max (res,j-i+1)
但是时间复杂度还是O(n²)
对于这类线性结构的问题,我们应该尽可能想办法把O(n²)的时间复杂度降为O(nlogn)甚至更低。
解法2:滑动窗口+哈希桶/哈希表
在上述解法中,计算机做了大量重复而无用的计算和判断工作。比如:在判断s[i+1,j]中是否存在重复字符和s[i,j]是否存在重复字符这二者的工作中,这种算法二者之间没有联系起相互之间的关系。
以[ i , j ]递推到[ i , j+1 ]为例:我们大可不必先用O(n)时间先证明一次[ i , j ]中有无重复元素,再用O(n)时间证明一次[ i , j+1 ]有无重复,这样是浪费算力。
如果[ i , j ]中无重复元素的话,我们可以将[ i , j ]范围内所有的字符值记录在某个容器中,再判断s[j+1]是否在容器中即可。
如果[ i , j ]中有重复元素的话,把s[i]对应的键值减少1,再让i++,判断容器中所有的字符是否唯一。若不唯一,重复该操作,直到唯一为止。
这就是滑动窗口(Sliding Windows)的核心思想,它也可以理解为 DP的一种形式。LeetCode上有相当多的题目都是这种套路。用伪码来描述就是
l = 0, r = 1 ,s[l] s[r]都丢入容器 for (;r < s.len;r++) while (s[r+1]在容器中) 容器中的s[l]-- l++ r++ 将s[r]丢入容器 res = max(res,r-l+1)
这里的算法利用了前期计算的结果作为基础,复杂度大大下降,成为线性的O(n),完全可以被接受了。
具体代码实现
class Solution { public: inline int max(int a, int b) { return a > b ? a : b; } int lengthOfLongestSubstring(string s) { int left = 0, right = 0; int len = s.length() - 1; if (len == -1) return 0; int res = 1; if (len == 0) return 1;//预处理一哈 bool bucket[128] = { false };//CHAR_MAX是127 bucket[s[0]] = 1; while (right < len) { while (bucket[s[right + 1]]) { bucket[s[left++]] = 0;//清空桶 } right++; bucket[s[right]] = 1;//把右边的值丢入桶 res = max(res, right - left + 1); } return res; } };
解法3:哈希表记录前缀值
还可以有别的写法吗?我不想嵌套内层的while循环。
当然可以
利用一个hashmap来存放每个字母最新出现的位置。若hashMap中显示已访问该值,则更新左值。
class Solution { public: int lengthOfLongestSubstring(string s) { vector<int> m(128, -1); int res = 0, left = -1; for(int i=0;i<s.length();i++){ left = max(m[s[i]], left);//若已经访问过这个点就更新左值 m[s[i]] = i; res = max(res, i - left); } return res; } };
时间复杂度同样是O(n)
- 【leetcode每日一题】【2019-04-10】3.无重复字符的最长子串
- LeetCode3. 无重复字符的最长子串(python)
- 【leetcode】3. 无重复字符的最长子串
- LeetCode 3. 无重复字符的最长子串
- Leetcode-3.无重复字符的最长子串(python)
- leetcode 3.无重复字符的最长子串
- Leetcode 3. 无重复字符的最长子串
- LeetCode 3.无重复字符的最长子串
- LEETCODE学习 -- 3.无重复字符的最长子串
- Leetcode3. 无重复字符的最长子串
- LeetCode 3. 无重复字符的最长子串
- LeetCode题解(python)-3.无重复字符的最长子串
- LeetCode 3. 无重复字符的最长子串 Python
- LeetCode 3. 无重复字符的最长子串
- LeetCode--3.无重复字符的最长子串
- Leetcode(C++)——3. 无重复字符的最长子串
- Leetcode每日一道 -- 无重复字符的最长子串
- LeetCode 3. 无重复字符的最长子串
- 【Leetcode】3. 无重复字符的最长子串[未解出]
- [Leetcode] 3.无重复字符的最长子串