LeetCode-#3-无重复字符的最长子串(Longest Substring Without Repeating Characters)

版权声明:一篇成长日记文章,没什么转载价值。 https://blog.csdn.net/zhaoyanga14/article/details/83049798

题目:

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

示例 1:

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

示例 2:

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

示例 3:

输入: "pwwkew"输出: 3解释: 无重复字符的最长子串是 "wke",其长度为 3。

     请注意,答案必须是一个子串,"pwke" 是一个子序列 而不是子串。


这个问题其实是在一个区间找没有重复字符最长子区间长度的问题。第一个方法看起来有点绕的话可以先尝试取理解第二种方法,比较易懂。

假设abcacbd字符串s是一个[a,b,c,a,c,b,d]的区间,最长无重复子串长度为len,记录每个无重复子串区间的起始下标start。

1、先从a开始,start=0,下标为1的b和它不一样,1-start=1,len=2;

2、接下里是下标为2的c,它和区间s[start,2)里的值没有重复的,所以2-start=2,len=3;

3、、然后是下标为3的a,糟了,它和下标为0的a重复了,没办法,这个区间终结了,只能从a的后一位开始新的区间s[1,3),所以start=1,3-start=2,len=3;

4、到下标为4的c时,在区间s[start,4)中出现它和下标为2的c重复,区间s[start,4)又终结了,新的区间从下标3开始,s[3,4);start=3,4-start=1,len=2;

5、到下标为5的b时,虽然前面有字符串前面有和它重复的字符,但不在区间s[3,4)中,所以无影响,继续,s[3,5);start=3,5-start=2,len=3;

最终,start=3,6-start=3,len=4;

最长无重复字符的子串,为”acbd”,长度为4。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); 
//  i用来循环字符串s中的字符,start用来记录子串起始的位置。
        for (int end = 0, start= 0; end< n;end++) {
//  判断是否出现重复值
            if (map.containsKey(s.charAt(end))) {
//  比较看看重复值的前者是否在start位置之后(下标大于start),在start之后的话,说明在当前的区间内,
//[start,end]中存在重复值,那就是end和之前的某个值(假设下标是A)重复了,这样的话[start,end]这个区
//间就不能用了,所以start就要变成A的下一个字符的下标map.get(s.charAt(end))。
//  如果重复值的前者在start位置之前,那么就不影响[start,end]区间,所以不用把值赋值给start。
                start= Math.max(map.get(s.charAt(end)), start);
            }
//  计算的子串长度,这里+1是为了加上end本身,比如start是0,end - start要比实际长度少1个,所以要+1。
            ans = Math.max(ans, end - start+ 1);
//  存放每个字符最后出现的位置的下一个字符的下标,用于上面start的赋值。
            map.put(s.charAt(end), end + 1);
        }
        return ans;
    }
}

下面这个也是用了这种思想,不过不是用哈希表来判断[start,end]区间有没有重复值了,而是使用循环判断,循环[start,end]区间的数,看看哪个和end位置的字符相同,有相同字符话说明这个区间就不能用了,就换成start = j+1,j是相同字符的位置。

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int ans=0;
        int start=0;
        char[] c=s.toCharArray(); 
        for(int end=0;end<c.length;end++){
			for(int j=start;j<end;j++){
				if(c[end]==c[j]){
					start=j+1;
					break;
				}
			}
//  这里其实是end-(start-1),因为start是子串起始字符的下一位的下标。
			ans=Math.max(ans,end-start+1); 
        }
        return ans;
    }
}

按理说,这种写法随着字符串的加长,循环的复杂度也会不确定,感觉不如上一个方法。但是就这个题目,它确实比上一个方法要快很多。

猜你喜欢

转载自blog.csdn.net/zhaoyanga14/article/details/83049798