• 3


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

    思路

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

    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;
        }
    }
    
  • 相关阅读:
    P3371 【模板】单源最短路径(弱化版)
    村村通
    P1551 亲戚题解
    P4467 [SCOI2007]k短路
    P2483 【模板】k短路([SDOI2010]魔法猪学院)
    POJ——2449 Remmarguts' Date
    P1337 [JSOI2004]平衡点 / 吊打XXX
    P1118 [USACO06FEB]数字三角形`Backward Digit Su`…
    P1621 集合
    P1514 引水入城
  • 原文地址:https://www.cnblogs.com/nzhl/p/6208882.html
Copyright © 2020-2023  润新知