LeetCode-3. Longest Substring Without Repeating Characters

1. 问题描述

Given a string, find the length of the longest substring without repeating characters.
Examples:

Given "abcabcbb", the answer is "abc", which the length is 3.
Given "bbbbb", the answer is "b", with the length of 1.
Given "pwwkew", the answer is "wke", with the length of 3.
Note that the answer must be a substring, "pwke" is a subsequence and not a substring.

2. 解法描述

2.1 暴力穷举

最直接的思路是遍历每个可能的子串,然后判断子串是否有重复字符,最后返回符合条件的各子串长度中的最大值,代码如下:

public static int lengthOfLongestSubstring1(String s) {
    int len = s.length();
    int ans = 1;

    for (int curr1 = 0; curr1 < len - 1; curr1 ++) {
        for (int curr2 = curr1 + 1; curr2 < len; curr2 ++) {
            if (isUnique(s, curr1, curr2)) ans = Math.max(ans, curr2 - curr1 + 1);
        }
    }

    return ans;
}

public static boolean isUnique(String s, int start, int end) {
    Set<Character> set = new HashSet<>(); // 集合内元素唯一性
    for (int i = start; i <= end; i ++) {
        Character ch = s.charAt(i);
        if (set.contains(ch)) return false;
        set.add(ch);
    }
    return true;
}

时间复杂度为 O(n3) ,空间复杂度为 O(min(m,n)) ,其中 n 为字符串长度,m为各子串中非重复字符个数。

2.2 优化版本

显然,暴力穷举法是不可接受的。
对于判断某元素是否重复这类问题,首先想到的是集合set(在暴力穷举法中的isUnique方法上已使用),另外,还有一种集合不易想到,那就是map(key值唯一)。

2.2.1 set版本

设置两个游标curr1curr2,两游标间的最大间隔即为待求结果。

public static int lengthOfLongestSubstring2(String s) {
    int len = s.length();
    Set<Character> set = new HashSet<>();
    int ans = 0, curr1 = 0, curr2 = 0;

    while (curr1 < len && curr2 < len) {
        if (set.contains(s.charAt(curr2))) {
            set.remove(s.charAt(curr1++));
        } else {
            set.add(s.charAt(curr2++));
            ans = Math.max(ans, curr2 - curr1);
        }
    }
    return ans;
}

时间复杂度为 O(2n)=O(n) ,空间复杂度同样为 O(min(m,n))

2.2.2 map版本

set版本的问题在于curr1不能直接移到已重复元素的上一位,而这个问题主要由集合set的存储结构所决定的。而map不仅能够存储值,还能够存储值所对应的下标。

public static int lengthOfLongestSubstring3(String s) {
    int len = s.length();
    Map<Character, Integer> map = new HashMap<>();
    int ans = 0;

    for (int curr1 = 0, curr2 = 0; curr2 < len; curr2++) {
        if (map.containsKey(s.charAt(curr2))) {
            curr1 = Math.max(curr1, map.get(s.charAt(curr2)) + 1);
        } else {
            ans = Math.max(ans, curr2 - curr1 + 1);
            map.put(s.charAt(curr2), curr2 + 1);
        }
    }

    return ans;
}

时间复杂度为 O(n) ,空间复杂度同样为 O(min(m,n))

参考

Longest Substring Without Repeating Characters

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值