找出字符串中不含重复字符的最长子串的长度

1. 题目

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

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

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

示例3:
输入:"pwwkew"
输出:3
解释:因为无重复字符的最长子串是:"wke"或"kew",所以其长度为3
注意:必须是子串的长度,子串是连续的字符,中间不能跳跃字符,如"pwke"是一个子系列,不是子串。

2. 解题思路

2.1 思路一:滑动窗口

窗口通常是在数组/字符串中由开始和结束索引定义的一系列元素的集合,即[i, j)(左闭,右开),而滑动窗口是可以将两个边界向某一方向“滑动”的窗口。

例如:
我们将[i, j)向右滑动1个元素,则它将变为[i+1, j+1)(左闭,右开)
HashSet存储当前处于窗口[i, j)(最初 j = i)中的字符,然后我们向右滑动索引j,如果它不在HashSet中,我们会继续滑动j,直到s[j]已经存在于HashSet中,此时没有重复的最长子字符串将会以索引i开头

HashSet存放当前处于滑动窗口中的字符,初始HashSet为空。
窗口的左边i不动,右边j向右滑动,依次遍历字符:j为指向字符的索引。
当j = 0时,遍历字符p,加入HashSet -- [p],则目前无重复字符的最大子串长度maxSubLength = 1
当j = 1时,遍历字符w,加入HashSet -- [p, w],则maxSubLength = 2

滑动窗口1.png

当j = 2时,遍历字符w,此时HashSet中已包含重复字符w,
则窗口的左边i向右滑,右边j不动,HashSet依次删除索引i所指向的字符,直到HashSet不再包含该字符w,
然后重新将遍历字符w加入HashSet中,启动窗口j继续右滑。

滑动窗口2.png

窗口的左边i不动,右边j继续向右滑动,依次遍历字符:j为指向字符的索引
当j = 3时,遍历字符k,加入HashSet -- [w k]
当j = 4时,遍历字符e,加入HashSet -- [w k e],则此时maxSubLength = 3

滑动窗口3.png

当j = 5时,遍历字符w,此时HashSet中已包含重复字符w,
则窗口的左边i向右滑,右边j不动,HashSet依次删除索引i所指向的字符,直到HashSet不再包含该字符w,
然后重新将遍历字符w加入HashSet中,启动窗口j右滑。
结束,则maxSubLength = 3

滑动窗口4.png

代码实现:

public static int lengthOfLongestSubstring(String s) {
    if (s == null || "".equals(s)) {
        return 0;
    }
    int n = s.length();
    Set<Character> set = new HashSet<>();
    int maxLength = 0;
    int i = 0;
    int j = 0;
    while (i < n && j < n) {
        if (!set.contains(s.charAt(j))) {
            set.add(s.charAt(j++));
            maxLength = Math.max(j - i, maxLength);
        } else {
            set.remove(s.charAt(i++));
        }
    }
    return maxLength;
}

2.2 思路二:优化的滑动窗口

针对上述的滑动窗口方法,不使用集合来判断一个字符是否存在,而定义字符到索引的映射map。
当找到重复字符时,可以立即跳过该窗口。

如果在[i, j)范围内有与s[j]重复的字符,索引为j',即[i, ... j', ... j)
我们不需要逐渐增加i,可以直接跳过[i, j']范围内的所有元素,并将i变为j' + 1

举例:
s = "pwwkew",当 j = 2时,窗口[0, 2)范围内有与s[2]重复的字符w,索引为1(j' = 1),我们可以直接跳过[0, 1]范围内的所有元素,将i变为2(j' + 1)

代码实现:

public static int lengthOfLongestSubstring(String s) {
  if (s == null || "".equals(s)) {
        return 0;
    }
    int n = s.length();
    Map<Character, Integer> map = new HashMap<>(16);
    int maxLength = 0;
    for (int i = 0,j = 0; j < n; j++) {
        if (map.containsKey(s.charAt(j))) {
            i = Math.max(map.get(s.charAt(j)), i);
        }
        maxLength = Math.max(maxLength, j - i + 1);
        map.put(s.charAt(j), j + 1);
    }
    return maxLength;
}

2.3 思路三:使用列表List存储不重复字符

依次遍历字符串 s 中的每次字符,若不是重复字符,加入一个列表list中,若是重复字符,则删除列表list中该重复字符以及前面的所有字符,然后再将该重复字符加入此列表list中。

在遍历的过程中统计出列表list中存储的最大字符个数,即为字符串 s 中不含重复字符的最长子串的长度。

代码实现

public static int lengthOfLongestSubstring(String s) {
    if (s == null || "".equals(s)) {
        return 0;
    }
    List<Character> list = new ArrayList<>();
    int n = s.length();
    int maxLength = 0;
    for (int i = 0; i < n; i++) {
        int index = list.indexOf(s.charAt(i));
        if (index == -1) {
            list.add(s.charAt(i));
            maxLength = Math.max(list.size(), maxLength);
        } else {
            for (int j = index; j >= 0; j--) {
                list.remove(j);
            }
            list.add(s.charAt(i));
        }
    }
    return maxLength;
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容