leetcode习题集——3. 无重复字符的最长子串

题目

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

示例 1:

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

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

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

算法1

public class P3_LongestSubstring {

    public int lengthOfLongestSubstring(String s) {
        if(s==null||s.length()==0){
            return 0;
        }
        int max = 1;
        HashMap<Character,Integer> kvMap = new HashMap<>();
        for(int i = 0;i<s.length();i++){
            for(int j = i;j<s.length();j++){
                char cur = s.charAt(j);
                if(kvMap.get(s.charAt(j)) ==null){
                    kvMap.put(s.charAt(j),j);
                    max = max > j - i + 1? max : j - i +1;
                }else{
                    max = max > j - i? max : j - i;
                    kvMap.clear();
//                    kvMap = new HashMap<>();
                    break;
                }
            }

        }
        return max;
    }

    public static void main(String[] args){
        System.out.println(""+new P3_LongestSubstring().lengthOfLongestSubstring("abcabcbb"));
    }
}

本题我首先想到的是用hashmap来判断是否重复,不过从运行时间上来看,这个应该不算是一个比较优秀的解法了,运行时间如下:
leetcode习题集——3. 无重复字符的最长子串_第1张图片
分析原因可能是hashmap反复查找键用掉了很多时间。

算法2

 public int lengthOfLongestSubstring(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++) {
            char cur = s.charAt(j);
            //找到当前字符出现的上一个位置
            i = Math.max(index[s.charAt(j)], i);

            //当前字符的当前位置和上次出现的位置差值,看是否比ans大,如果是则取更大值
            ans = Math.max(ans, j - i + 1);

            //index[]数组表示当前字符在String中出现的最大下标
            index[s.charAt(j)] = j + 1;
        }
        return ans;
    }
    public static void main(String[] args){
        System.out.println(""+new P3_LongestSubstring2().lengthOfLongestSubstring("abcabcbb"));
    }

解读:
这个算法只遍历了一次字符串,在遍历时动态找到最大不重复子串。
循环内的关键代码

index[s.charAt(j)] = j + 1;

这里index[]数组表示当前字符在String中出现的最大下标

i = Math.max(index[s.charAt(j)], i);

这里i是取 当前字符的上次出现的最大下标和 上次 i的值得较大值,为什么要这样比较呢?距离如下:

  • 串1:abca
    当遍历到第二个a时,i = 0,index[s.charAt(j)] = 1,这里取较大的index[s.charAt(j)],意为遍历到第二个a时,到上一次出现a之间的串即为不重复的串。
  • 串2:zabcaz
    当遍历到第二个a时,i取完较大值为i = index[s.charAt(j)] = 2,当遍历到第二个z时,index[s.charAt(j)] = 1 ,i为2,因此取i为2。这里的意义是如果简单的去两个z之间的子串话,子串内的子串有可能还有重复的,当取了较大值后,能保证j和i之间的串一定是不重复的。

ans = Math.max(ans, j - i + 1);

循环时得出最大子串长度,j为当前下标,i=
Max{该字符上次出现的最大下标值,前一个i(之前其他字符的上一个最大下标值)},下标相减+1即为长度。

运行时间如下,速度提升了4倍:
leetcode习题集——3. 无重复字符的最长子串_第2张图片

你可能感兴趣的:(算法,java,Hashmap,子串,数组,算法,HashMap)