LeetCode3 LongestSubstringWithoutRepeatingCharacters

LeetCode3 LongestSubstringWithoutRepeatingCharacters

题目描述

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

示例1:

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

示例2:

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

示例3:

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

解答

解法一:滑动窗口_1

基本思路是,利用滑动窗口,移动右边界直到下一个字符x在窗口内出现过,此时记录窗口长度,用以更新所求子串长度,然后移动左边界,可以一个一个移动,也可以一次性移到窗口内字符x出现的位置上。

下面的代码是利用String类里面的基本方法substring和contains。看着很简洁易懂,但是实际上substring 方法容易产生大量字符串对象(只有在返回字符串本身时返回原对象,否则返回真子串时,会new新对象)。此代码是一个一个移动的左边界。

private static int solve1(String s){
    int len = s.length();
    int l=0,r=0;  //子串从[l,r]处
    int maxLen=0;
    if (len==1)
        return len;
    while (l<len ){
        if(r+1< len && !s.substring(l,r+1).contains(s.charAt(r+1)+"")){
            r++;
            maxLen = Math.max(maxLen, r-l+1);
        }else{
            l++;
        }
    }
    return maxLen;
}
解法二:滑动窗口_2

与解法一基本思路一样,只是需要开辟一个额外256个空间的数组(数组大小可以根据题目要求来定,26:a-z或者A-Z; 128:ASCII码,256:扩展的ASCII码)。利用每个字符的ASCII码来定在数组中的索引,存储的值是该字符出现的次数。代码比较简洁,空间也比较小。

private static int solve1_1(String s){
    int[] freq=new int[256];
    int maxLen =0, len = s.length();
    int l=0,r=-1;  //子串从[l,r]处
    while (l<len){
        if (r+1<len && freq[s.charAt(r+1)]==0){
            r++;
            freq[s.charAt(r)]++;
        }else {
            freq[s.charAt(l)]--;
            l++;
        }
        maxLen = Math.max(maxLen, r-l+1);
    }

    return maxLen;
}
解法三:滑动窗口_3(官方题解)

思路上还是滑动窗口基本思路。但是这个就用了优化:当子串s1遇到重复字符x时,我们不需要逐一去更新左指针l的值, 而是直接跳到子串中重复字符x’的位置上,这样就节省了一部分时间。

本代码来自官方题解,大意是利用一个hashMap来存储各个字符的最新出现的索引位置,当出现重复字符时,直接将左边界 i 跳到原索引的后一位,再更新该索引。

public static 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++) {
        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);
    }
    return ans;
}
解法四:滑动窗口_4(官方题解)

同样用了滑动窗口优化。本代码来自官方题解,只是将map换成了整型数组。用一个整型数组代替map来存储每个字符的最新出现的索引位置,字符在数组中的位置由ASCII码计算,存储的是最新出现的字符在字符串中的位置索引,当出现重复字符时,直接将i跳到原索引的后一位,再更新该索引。个人觉得比解法三要好一些,毕竟hashmap的存取过程还是需要一些时间的,而数组访问是O(1)。

public int lengthOfLongestSubstring2(String s) {
    int n = s.length(), ans = 0;
    int[] index = new int[128]; // current index of character
    // try to extend the range [i, j]
    for (int j = 0, i = 0; j < n; j++) {
        i = Math.max(index[s.charAt(j)], i);
        ans = Math.max(ans, j - i + 1);
        index[s.charAt(j)] = j + 1;
    }
    return ans;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值