前两天去爱丁堡玩了一波, 所以就没更新...

思路

这道题其实其实我一开始并没有想出来, 我大概说下自己的思维轨迹 :

  1. 一开始我没理清题目, 首先维护一个表用来记录某个字符串是否出现过, 然后遍历字符串, 直到碰到两个相同的字符, 此时所遍历的长度即为最大值. 这里我直接忽略了当最大不重复字符串出现在原字符串中部的情况, 刚写完我自己试着测试样例的时候就发现了这个问题.
  2. 我开始尝试着维护两个表, 一张与思路1中作用相同, 另一张用来记录该位置的字符距离下一次出现的长度, 如果不再出现则为0, 然后再一次遍历字符串, 维护左右两个指针, 正常情况下左指针不动, 没遍历一个点, 如果这个点的重复出现位置在右指针之前, 就跟新右指针为这个点的位置. 但是这里仍然存在思维漏洞, 当遍历到右指针位置时, 此时应该将左指针移动到与右指针所指字母重复的那个字母的位置, 但是一旦更新左指针, 这里暴露出我的思路用漏洞 : 我无法判断继续往下遍历出现的字母是否在之前出现过, 唯一的解决方式是将循环指针拉回到当前左指针的位置再进行遍历, 这种思路可以做, 但是时间复杂度将远远超过O(n)的数量级.
  3. 我分析思考了下, 突然我发现这道题其实是一个动态规划的问题. 我最后的想法是 : 维护两个指针表示这个最长字符串的起点和终点, 用一张表记录当前以及出现过的字母, 每出现一个新的点, 我查看这个字母在之前是否已经出现过, 若没有, 在表中记录即可, 若出现, 首先更新最长长度(比较max和right - left), 然后将左指针移动至该字母(出现了两次, 这里指前面的那个)的前方, 同时更新表, 移除左指针移动过程中扫过的字母(这些字母已经从最长字符串中移除了), 然后继续遍历即可.

实现

实现上并没有什么难度.

提交

一次AC.

代码

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int length = s.length();

        int[] map = new int[256];
        int left, right, max;

        left = right = max = 0;
        for(; right < length; ++right){
            if(map[s.charAt(right)] == 1){
                max = max >= right - left ? max : right - left;
                while(s.charAt(left) != s.charAt(right))    map[s.charAt(left++)] = 0;
                ++left;
            }
            else{
                map[s.charAt(right)] = 1;
            }
        }
        max = max >= right - left ? max : right - left;
        return max;
    }
}

最佳实现

我上面的做法用了两次遍历(一次左指针一次右指针), 但是可以优化为只遍历一次 : 这里他用哈希表记录每个字母出现的位置(实际上是当这个字母发生重复时i需要被更新到的位置, 也就是该字母位置的后一个位置). 一旦出现重复字母, 只需要判断较前的字母是否出现在i(其实就是左指针)之后, 如果是之后, 我们就把左指针更新到用新的位置, 否则不用更新. 此时只需要一次遍历数组即可.

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        int n = s.length(), ans = 0;
        Map<Character, Integer> map = new HashMap<>(); // current index of character
        // try to extend the range [i, j]
        for (int j = 0, i = 0; j < n; j++) {
            if (map.containsKey(s.charAt(j))) {
                i = Math.max(map.get(s.charAt(j)), i);
            }
            ans = Math.max(ans, j - i + 1);
            map.put(s.charAt(j), j + 1);
        }
        return ans;
    }
}
posted on 2016-12-21 19:47  内脏坏了  阅读(159)  评论(0编辑  收藏  举报