leetcode:Longest Substring Without Repeating Characters

问题描述:

Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.

原问题链接:https://leetcode.com/problems/longest-substring-without-repeating-characters/

问题分析

    这个问题看起来还是比较简单的。需要找一个字符串里最大不包含重复元素的子串。我们可以根据一些串的示例来分析一下:

     假定我们有如下的一个字符串:

      

     我们最初的想法可以是这样,通过将每个字符和它所在的索引保存到一个map里,每次将一个元素加入到map的时候事先判断一下map里是否存在该字符,如果存在则发现有重复的元素,需要做一些处理。否则直接将该元素和它所在的索引加入到map中。既然要取得最大的子串长度,我们需要有一个变量来记录当前串的起始位置以及当前的结束位置。

     在上述的示例中,假设分别以i, j表示当前串的开始和结束。当碰到一个重复的元素时,其情景如下图:

     

     这个时候我们该怎么办呢?为了计算最大的子串,我们应该将起始点移到这个已经存在的这个节点后面。也就是b这个位置上。也就是如下图这样:

    

    这个时候,我们需要更新原来那个重复元素映射的新位置,也就是将a映射的值设置为j。当然,因为前面这个示例有一点特殊,还有一个地方我们忽略了。就是假设i这个元素它并不是后面找到重复的地方,而是在它稍微后面一点的地方,比如下图这样:

    

    这个时候,我们碰到重复元素b,应该将i移到b后面。但是这个时候我们也应该修改map。因为map里应该只保存从i到j之间的所有元素,所以从i到b之间的所有元素应该被移除掉。

    这样,经过这些讨论我们就有了这么一个思路。首先记录起始和终止标识i, j为0。然后j开始向后遍历,每次遍历就检查是否在map里存在该元素。如果不存在则直接加入到map中。如果存在,则从i到它找到存在的那个元素之间将这些元素从map里去掉,然后设置i为重复元素后面的那个位置,再更新冲突的位置为j。这样可以得到如下的代码:

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        if(s == null || s.length() == 0) return 0;
        int len = 0;
        Map<Character, Integer> map = new HashMap<>();
        for(int i = 0, j = 0; j < s.length(); j++) {
            Character c = s.charAt(j);
            if(map.containsKey(c)) {
                int pos = map.get(c);
                for(int k = i; k <= pos; k++) map.remove(s.charAt(k));
                i = pos + 1;
            }
            map.put(c, j);
            len = Math.max(len, j - i + 1);
        }
        return len;
    }
}

     总体来说,这个解法的时间复杂度为O(n)。

总结

    这个问题并不复杂,主要是需要细心的分析一下就可以了。把图画出来就好办。

猜你喜欢

转载自shmilyaw-hotmail-com.iteye.com/blog/2278675