LeetCode第[3]题(Java):Longest Substring Without Repeating Characters 标签:Linked List

题目中文:没有重复字符的最长子串

题目难度:Medium

题目内容

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.

翻译

给定一个字符串,计算得到最长子字符串的长度,而子串内不能重复字符。

例子: 

给定“abcabcbb”,答案是“abc”,长度为3。

给定“bbbbb”,答案是“b”,长度为1。

给定“pwwkew”,答案是“wke”,长度为3。注意,答案必须是子字符串(连续的),“pwke”是子序列,而不是子字符串。

 

思路:应为需要的是子串(连续),所以双重循环就可以遍历每一个子串,再用一个函数来判断这个子串内部是否有重复,没有则更新最新的长度

我的代码

 1     public int lengthOfLongestSubstring(String s) {
 2         int n = s.length();  // size(),length()这类函数不像变量length,这也是要计算的,当调用一次以上,赋值给一个变量减少复杂度
 3         int ans = 0;
 4         for (int i = 0; i < n; i++) {
 5             for (int j = i + 1; j <= n; j++) {
 6                 if (isUnique(s, i, j)) {
 7                     ans = Math.max(ans, j - i);        // 如果唯一,则更新ans
 8                 }
 9             }
10         }
11         return ans;
12     }
13 
14     public static boolean isUnique(String s, int start, int end) {
15         Set<Character> hset = new HashSet<Character>();
16         for (int i = start; i < end; i++) {
17             hset.add(s.charAt(i));
18         }
19         return hset.size() == (end - start) ? true : false;        // 如果Set的大小没变说明都是唯一的
20     }

982 / 983 test cases passed.  Status: Time Limit Exceeded 

超时了。。。明显这个算法复杂度为O(n3),确实大了点。。。

编码期间问题

1、程序的边界问题困扰了很久,一开始isUnique方法我是设置从 i 到 j 都判断,j到n-1结束,结果发现这样子需要加很多边界判断条件,例如输入是“C”就一个,那么 j 从下标1开始直接就越界根本不会进入循环体。又或者全是同一个字符“cccccccccc”,isUnique只会一直false,ans也不会更新。偷看了下参考答案,发现第一个和我几乎一样,仔细一看发现它的判唯一范围是从 i 到 j 的前一个字符, j的范围从 i+1 一直到 n,这样一来就总会进入循环体,并且ans至少更新一次。

 

答案一

code略

和我的几乎一样就是判断唯一的方法里它是这么写的:

    public boolean allUnique(String s, int start, int end) {
        Set<Character> set = new HashSet<Character>();
        for (int i = start; i < end; i++) {
            Character ch = s.charAt(i);
            if (set.contains(ch)) return false;
            set.add(ch);
        }
        return true;
    }

可能比我的算法复杂度低一点,因为发现重复的时候它可以直接返回,而我那个是全部添加后才能判断重复。记住set、map都有contains功能

 

答案二

 1     public static int lengthOfLongestSubstring2(String s) {
 2         int n = s.length(), ans = 0;
 3         Map<Character, Integer> map = new HashMap<Character, Integer>();
 4         for (int j = 0, i = 0; j < n; j++) {
 5             if (map.containsKey(s.charAt(j))) {
 6                 i = Math.max(map.get(s.charAt(j)), i);
 7             }
 8             ans = Math.max(ans, j - i + 1);
 9             map.put(s.charAt(j), j + 1);
10         }
11         return ans;
12     }

 

983 / 983 test cases passed.  Runtime: 66 ms    beats  25.38%   算法复杂度:O(N)  

思路:利用map的key-value结构存储值以及对应顺位(下标+1),然后每次指针(j)下移的时候都判断是否已经包含了此字符,如果是则将 i 的值更新,所以每次ans都是取最大的 i 到 j (包括j)的长度。

  所以而 i 指向的一直是不包含重复的子串开头,而 j 指向就是结尾。ans的每次更新,保证了ans是最大的长度。

  例如 abcdaa

  当 j = 4时,发现map内有此时 j 指向的a,所以更新 i 的值,表明之前的a在顺位第 1 个,所以ans就等于新a的位置(j)减去老a的位置(顺位 i -1),所以相当于 j - i +1 = 4。

  当 j = 5时,发现map内有此时 j 指向的a,所以更新 i 的值,表明之前的a在顺位第 5 个,所以ans_temp = 5-5+1 = 1,取max ,ans最终等于4.

为什么不直接存下标?

  如果存储的是下标,那么最后更新的ans也只能是 j - i (新位置减去老位置),假如此时整个字符串内都没有重复,那么最后的答案就是length - 1 - 0 ,因为只有当有更新的时候才能下标直接相减。

 

答案三

 1     public int lengthOfLongestSubstring(String s) {
 2         int n = s.length(), ans = 0;
 3         int[] index = new int[256]; // current index of character
 4         // try to extend the range [i, j]
 5         for (int j = 0, i = 0; j < n; j++) {
 6             i = Math.max(index[s.charAt(j)], i);
 7             ans = Math.max(ans, j - i + 1);
 8             index[s.charAt(j)] = j + 1;
 9         }
10         return ans;
11     }

 

983 / 983 test cases passed.  Runtime: 66 ms    beats  83.43%   算法复杂度:O(N)  

其实思想和方法二差不多,有点取巧性质。。。因为字符都能用ascall码表示,而ascall码一共就256个,每一个代表一个字符,(因为后128个键盘输入不了,用128也行)所以直接使用一个int数组当哈希表使用,降低了哈希表的寻址时间复杂度。

以后遇见hash表的key为单个字符时,都可以想到用int[256]来替代map.get(*);

posted on 2018-03-08 17:46  清风吹斜阳  阅读(610)  评论(2编辑  收藏  举报

导航