zoukankan      html  css  js  c++  java
  • [LeetCode] 3. 无重复字符的最长子串

    传送门:[LeetCode] 3. 无重复字符的最长子串

    题目描述

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

    示例 1:

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

    示例 2:

    输入: "bbbbb"
    输出: 1
    解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。

    示例 3:

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

    分析与代码

    • 题目要求最长子串,子串就必须是连续的。
    • 变量 i 表示当前子串的起始下标,变量 j 表示当前子串的结束下标,变量 res 保存最大长度,即为循环过程中 j - i 出现的最大值。

    解法一:滑动窗口

    • 我们可以使用 HashSet 来保存已经加入当前子串中的字符。
    • 每次遍历,先判断 HashSet 中是否存在当前字符,若不存在,则加入到 HashSet 中,res 更新,j 加1,即向右扩大滑动窗口一位;若存在,HashSet 移出 i 下标的字符,i 加 1,即丢弃滑动窗口最左的一位。

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int res = 0;
            Set<Character> set = new HashSet<>();
            int i = 0, j = 0;
            while (j < s.length()) {
                if (!set.contains(s.charAt(j))) {
                    set.add(s.charAt(j));
                    res = Math.max(res, j - i + 1);
                    j++;
                } else {
                    set.remove(s.charAt(i++));
                }
            }
            return res;
        }
    }
    

    解法二:优化的滑动窗口

    • 我们也可以使用 HashMap 来优化,保存字符的同时,把该字符的下标也保存。
    • 每次遍历,先判断 HashMap 中是否已存在该字符,若存在,我们用 j' 表示该重复字符的前一个下标,我们要改变 i,这次就不是加1加1地改变,而是跳过[i,j']这一段,直接移动到 j‘ + 1 ,若不比 i 大,不需移动;即i = Math.max(i, map.get(s.charAt(j)) + 1)
    • 更新 res,存入当前字符和下标到 HashMap 中,不管是否重复都需要,重复则更新索引,相当于丢弃前一个重复字符,保存该重复字符最后出现的位置。

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int res = 0;
            Map<Character, Integer> map = new HashMap<>();
            int i = 0, j = 0;
            while (j < s.length()) {
                if (map.containsKey(s.charAt(j))) {
                    i = Math.max(i, map.get(s.charAt(j)) + 1);
                }
                res = Math.max(res, j - i + 1);
                map.put(s.charAt(j), j);
                j++;
            }
            return res;
        }
    }
    

    其实也可以不用containsKey(key)方法判断,getOrDefault(key,defalutValue)获取,默认值 -1。

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int res = 0;
            Map<Character, Integer> map = new HashMap<>();
            int i = 0, j = 0;
            while (j < s.length()) {
                i = Math.max(i, map.getOrDefault(s.charAt(j), -1) + 1);
                res = Math.max(res, j - i + 1);
                map.put(s.charAt(j), j);
                j++;
            }
            return res;
        }
    }
    

    解法三:数组代替HashMap

    • 我们知道当 key 可为数值且范围够小时,可用数组代替 HashMap,下标当作 key,数组值当作 value。
    • 常用表如下:int [26];int [52];用于字母,int [128]用于 ASCII 码,int [256]用于扩展 ASCII 码,而这题的范围就是128个字符。
    • 这里表里保存的直接就是字符的下一个下标,而不是该字符的下标,ht[s.charAt(j)] = j + 1;因为数组默认值为0,若保存该字符下标,则i = Math.max(i, ht[s.charAt(j)])这里的ht[s.charAt(j)]需要多加 1,而数组默认值为 0,会出现问题。方法二中的 HashMap 保存字符的下一个下标也是可以的。

    代码:

    class Solution {
        public int lengthOfLongestSubstring(String s) {
            int res = 0;
            int[] ht = new int[128];
            int i = 0, j = 0;
            while (j < s.length()) {
                i = Math.max(i, ht[s.charAt(j)]);
                res = Math.max(res, j - i + 1);
                ht[s.charAt(j)] = j + 1;
                j++;
            }
            return res;
        }
    }
    

    小结

    这道题主要学习了滑动窗口的思想,其实我感觉和双指针有点类似?感觉优化后的滑动窗口才是真正的滑动窗口。

    HashMap 在 key 可为数值且范围够小时,可用数组代替。



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    判断一个对象是否为空
    viewflipper的高度设置
    Android利用ViewFlipper实现屏幕切换动画效果
    锁屏状态下点亮屏幕,并弹出闹钟提示信息
    android如何取消闹铃
    luogu P1880(区间dp)
    luogu P2014 选课(树形dp)
    luogu P1122(树形dp)
    luogu P1352 (树形dp)
    luogu P1541 (dp)
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-3.html
Copyright © 2011-2022 走看看