LeetCode 3. Longest Substring Without Repeating Characters 无重复字符的最长子串 Java实现

先上题:


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

示例:

给定 "abcabcbb" ,没有重复字符的最长子串是 "abc" ,那么长度就是3。

给定 "bbbbb" ,最长的子串就是 "b" ,长度是1。

给定 "pwwkew" ,最长子串是 "wke" ,长度是3。请注意答案必须是一个子串"pwke" 是 子序列  而不是子串。


问题的目标在于找寻最大的连续子字符串,所以可以把问题转换为找两个索引,分别为最大子字符串的头部索引和尾部索引。

针对每个字符在处理过程中的存储我们用哈希表来存储,主要是因为找寻字符有没有出现过的操作会变成O(1)的复杂度,可以提高算法时间性能。

在更新当前两个索引值的过程中主要会碰到两种情况:

  1. 当前位置的字符之前出现过了:去哈希表里面找这个字母最后出现过的位置,然后用这个位置的下一位置和当前的头部索引比较,取大的那个。然后更新这个字母最后出现的位置。
  2. 当前位置的字符没有出现过:根据当前的头部索引和尾部索引算个子字符串长度,和当前最优解比大小,保留大的那个,然后跳转到下个字符。

上代码:

import java.util.*;
public class LengthOfLongestSubstring {
    public int lengthOfLongestSubstring(String s) {
        int result = 0, j = 0;
        if (s == null || s.length() == 0) return result;
        // 如果想直接获得之前处理过的数字或者字符的话,可以想想哈希表:)
        Map<Character, Integer> substring = new HashMap<Character, Integer>();
        char[] chs = s.toCharArray();
        for (int i = 0; i < chs.length; i ++) {
            if (substring.containsKey(chs[i]))
                j = Math.max(j, substring.get(chs[i]) + 1);
            substring.put(chs[i], i);
            result = Math.max(result, i - j + 1);
        }
        return result;
    }
}
2018/04/23 更新


应我家宝宝的要求,要我用动态规划去做这个题,本来以为这道题不能用动态规划做,但是做着做着发现还真的可以做,但是这个O(N^2)的时间复杂度有点高,LeetCode也没有AC,不知道有没有优化的好方法。

主要的思路就是创建一个二维布尔数组a去保存处理的过程值:

                            

i表示子字符串头部的索引,j表示子字符串尾部的索引,里面存的布尔值表示这个以i为头部索引,以j为尾部索引的子字符串是不是不包含重复的字符,如果包含就置True,不包含则置False。

动态规划的状态转移公式如下所示:

    a[i][j] = a[i + 1][j] && a[i][j - 1] && (s.charAt(i) != s.charAt(j))

举个例子:如果a[i][j]对应的子字符串为abb,那我判断这个字符串是否为真是通过检查abbb是否为真,可以看到ab是符合条件的字符串,但是bb并不符合,所以a[i][j]为false。当然,如果a[i + 1][j]和 a[i][j - 1]这两项都为真的话,说明除了头尾字符是否相同未知之外,其他字符都是和头尾字符不一样的,所以我们只要判断头尾字符是否相同即可。

接下来就是代码时间了,感觉可以进一步优化:

import java.util.*;
public class LengthOfLongestSubstring {
    public int lengthOfLongestSubstringDP(String s) {
        int result = 0;
        if (s == null || s.length() == 0) return result;
        boolean[][] isSubstring = new boolean[s.length()][s.length()];
        for (int i = isSubstring.length - 1; i >= 0; i --) {
            for (int j = i; j < isSubstring[0].length; j ++) {
                if (i == j || (isSubstring[i + 1][j] && isSubstring[i][j - 1] && s.charAt(i) != s.charAt(j))) {
                    isSubstring[i][j] = true;
                    result = Math.max(result, j - i + 1);
                }
            }
        }
        return result;
    }
}


猜你喜欢

转载自blog.csdn.net/zhangzhetaojj/article/details/80044237