题目:
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.

解法1:
核心思想是当发现有重复的字母,就把重复字母第一次出现位置以及之前的字母都删掉,这样就保证剩下的string中没有重复的字母了。用hashmap来记录字母出现的index,可以快速查找出字母是否重复出现,并定位到它出现的位置,方便做删除之前字母的操作。
代码1:

public void deletePrevious(Map<Character, Integer> map, String s, int start, int end) {
        for (int i = start; i <= end; i++) {
            char c = s.charAt(i);
            map.remove(c);
        }
    }
    public int lengthOfLongestSubstring(String s) {
        int result = 0;
        if (s.length() == 0) return result;
        
        Map<Character, Integer> map = new HashMap<Character, Integer>();
        int start = 0;
        int len = 0;
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (map.containsKey(c)) {
                int index = map.get(c);
                //把从重复的index开始,前面所有的数都在map里去掉,并记下新的start
                deletePrevious(map, s, start, index);
                start = index + 1;
                map.put(c, i);
                //删掉后的len是当前i减去删掉数的index
                len = i - index;
            } else {
                map.put(c, i);
                len++;
            }
            result = Math.max(result, len);
        }
        return result;
    }

又看了其他人的解法,感觉有很好的思路就拷贝过来了。

解法2:
我用j, i来记录最后不重复string的开始点和当前点,当我找到一个重复出现的字母,我判断一下j是否要更新,如果这个重复字母出现第一次的位置比j小,那么说明至少从j开始才能保证没有重复字母;如果这个重复字母出现第一次的位置比j大,那么将j更新到这个位置的后一位,作为新的开始点。然后把这个字母的index更新。这里省去了我上面说的删除之前所以map中的值,因为就算出现了重复的值,我也还是从j开始算,并且我更新这个值的新index后,原来那个就相当于自动删除了。
代码2:

public int lengthOfLongestSubstring(String s) {
        if (s.length()==0) return 0;
        HashMap<Character, Integer> map = new HashMap<Character, Integer>();
        int max=0;
        for (int i = 0, j = 0; i < s.length(); i++) {
            if (map.containsKey(s.charAt(i))) {
                //这里j是记录满足条件的start,当发现有重复的数时,应从重复数第一次出现的位置向后一位开始记,但同时要保持从j开始向后所有数都不重复,就得取最大值
                j = Math.max(j, map.get(s.charAt(i)) + 1);
            }
            //更新重复出现数的index值
            map.put(s.charAt(i), i);
            max = Math.max(max, i - j + 1);
        }
        return max;
    }

解法3:
这里思路跟解法2一样,只不过他巧妙利用cache,因为所以字母就127个,那个我用256的空间就肯定能记录所有的点。比如就算最极端,cache(0)是‘a',一直到cache(255)才双出现‘a’,我的空间也是够的。

public int lengthOfLongestSubstring(String s) {
        int result = 0;
        int[] cache = new int[256];
        for (int i = 0, j = 0; i < s.length(); i++) {
            j = (cache[s.charAt(i)] > 0) ? Math.max(j, cache[s.charAt(i)]) : j;
            //注意因为stirng的index是从0开始,但是我们判断这个字母是否在cache里也用这个字母的cache值是否来判断,所以我们把每个存进cache里的字母的index + 1, 这样存的就是它的下一个数的index。
            cache[s.charAt(i)] = i + 1;
            result = Math.max(result, i - j + 1);
        }
        return result;
    }

guoluona
199 声望14 粉丝

« 上一篇
1. Two Sum