1. 题目

无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。

输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。

输入: “pwwkew”
输出: 3
解释: 因为无重复字符的最长子串是 “wke”,所以其长度为 3。
请注意,你的答案必须是 子串 的长度,”pwke” 是一个子序列,不是子串。

2. 解题思路

解法1

滑动窗口:当循环一个数组时,取2个索引ij,都从0开始递增,通过ij的变化,来获取所有的子数组。

这里,可以使用滑动窗口来获取子串,使用Set集合来判断子串元素是否重复。

使用滑动窗口先滑动j获取到子串S[ij),如果S[ij)被认定为无重复,我们只需要检查S[j]是否存在于子串S[ij)中即可,若不存在,将S[j]存放在Set中,并将j往后移一位,如果存在,我们需要返回来判断S[ij)中,是哪一位与S[j]重复,这时,我们需要往前滑动i,再判断S[j]是否存在新的S[i,j)中,重复上面操作,直到循环结束。

解法2

滑动窗口优化

在循环时,我们保存值-索引到HashMap中,若不存在,将S[j]-j存放在HashMap中,并将j往后移一位,如果存在,取出存在的索引j',直接跳过S[ij'),将i置为j'+1

3. 题解

解法1
  1. int lengthOfLongestSubstringMethod1(String s) {
  2. //初始化滑动窗口索引i, j, 结果
  3. int i = 0, j = 0, result = 0;
  4. //新建HashSet存放子串
  5. Set<Character> set = new HashSet<>();
  6. //循环串
  7. while(i < s.length() && j < s.length()) {
  8. if(set.contains(s.charAt(j))) {
  9. //先删除i
  10. set.remove(s.charAt(i));
  11. //i往前滑动
  12. i ++;
  13. } else {
  14. //j存放到Set中
  15. set.add(s.charAt(j));
  16. //j往前滑动
  17. j ++;
  18. //计算结果
  19. result = Math.max(result, j - i);
  20. }
  21. }
  22. return result;
  23. }

解法2
  1. int lengthOfLongestSubstringMethod2(String s) {
  2. //定义结果
  3. int result = 0;
  4. //新建K-V存放元素-索引
  5. Map<Character, Integer> map = new HashMap<>();
  6. //循环数组
  7. for(int i = 0, j = 0; j < s.length(); j ++) {
  8. Character currentChar = s.charAt(j);
  9. if(map.containsKey(currentChar)) {
  10. //存在时,直接跳过i-j'
  11. i = Math.max(map.get(currentChar) + 1, i);
  12. }
  13. result = Math.max(result, j - i + 1);
  14. map.put(currentChar, j);
  15. }
  16. return result;
  17. }

HashMap可以转为数组进行处理

int[26]:用于字母 ‘a’ - ‘z’ 或 ‘A’ - ‘Z’

int[128]:用于ASCII码

int[256]:用于扩展ASCII码

4. 分析

解法1

时间复杂度:O(n)

空间复杂度:O(n)

解法2

时间复杂度:O(n)

空间复杂度:O(n)

5. 知识点

滑动窗口

HashSet

HashMap

数组