LeetCode 3.Longest Substring Without Repeating Characters 无重复字符的最长子串 Python3 三种解法
无重复字符的最长子串 Python3 三种解法)
LeetCode 3.Longest Substring Without Repeating Characters 无重复字符的最长子串 Python3 两种解法
原题在这里
https://leetcode.com/problems/longest-substring-without-repeating-characters/
除了暴力匹配讨论区就是各种滑动窗口的实现,尽量多搬运。
暴力匹配
确实很暴力,复杂度也很高。思路就是枚举所有不重合的情况。因为用了哈希的dict少了一个扫描我的复杂度,运算复杂度比官网稍丢一点点。但是也高达 O ( n 2 ) O(n^2) O(n2),胜在代码简单好懂。按照不重复的规则[abbcab]会拆分出[ab][b][bca][ab]再全部拿来比较。
def lengthOfLongestSubstring(self, s):
max_length = 0
for i in range(len(s)):
dict = {s[i]:0}
for j in range(i + 1, len(s)):
try:
test = dict[s[j]]
except Exception as e:
dict[s[j]] = j
else:
break
if len(dict) > max_length:
max_length = len(dict)
return max_length
https://leetcode-cn.com/problems/two-sum/solution/liang-shu-xiang-jia-by-
滑动窗方法一
先贴官网Java版本。时间窗和暴力匹配的区别举个栗子还是很明白的。再使用的字符串为[abbcab]的栗子,暴力匹配由每个索引位置为一轮,每个索引都要对自己后面的字符再做几次判断,才能依次得到[ab],[b],[cab],[bca],[ab][a],每一轮都会与上一轮比较子串的长度。 但是对于滑动窗方法来说,计算的时候实际使用的是窗口的范围长度i-j,在用于储存窗口的HashSet上执行add和remove,改变窗子的大小,每一轮i或者j前进一格,从滑动路径的历史来看,那些一直位于窗口中的字符的索引就省却了重启重算。暴力匹配每个大循环肯定要有索引位数次,但是这个栗子中左右边界分别只进位了2次和4次。
为了画图和优化版对比新取一个[abcdbc]的栗子。左边界进位3次,右边界进位刚好是字符串的长度。
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length();
Set<Character> set = new HashSet<>();
int ans = 0, i = 0, j = 0;
while (i < n && j < n) {
// try to extend the range [i, j]
if (!set.contains(s.charAt(j))){
set.add(s.charAt(j++));
ans = Math.max(ans, j - i);
}
else {
// clear duplicate value in the set
// i move one step
set.remove(s.charAt(i++));
}
}
return ans;
}
}
Python Deque 滑动窗方法
另外官网上找到python deque实现的版本。基本思想类似。特别的点就是利用deque双向特性,对重复的值的位置做判断,然后位移窗。
class Solution:
# window
def lengthOfLongestSubstring(self, s):
"""
:type s: str
:rtype: int
"""
dequeList = deque()
uniqueList = []
globalMax = 0
for char in s:
if char in dequeList:
# char at head
if dequeList[0] is char:
# make sure only one char
dequeList.popleft()
dequeList.append(char)
else:
# get char at head
while dequeList[0] is not char:
dequeList.popleft()
dequeList.popleft()
dequeList.append(char)
else:
dequeList.append(char)
globalMax = max(globalMax, len(dequeList))
return globalMax
滑动窗方法二
官网自己给出了上面方法的一个优化,HashSet升级成为HashMap用于存储每个字符对应的位置。HashMap取代HashSet存储每个char对应的位置窗口左边方向进位一步到位。
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>();
// current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
// directly move i to the location of duplication value
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1); // cover same value
}
return ans;
}
}
```