Leetcode 03 无重复字符的最长子串

148 阅读2分钟

GitHub-LT-03-源码 :large_blue_diamond:哈希表 :large_blue_diamond:最长子串 :large_blue_diamond:重复元 :large_blue_diamond:滑动窗口

问题描述

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

解法1: 死窗口-便于理解

  • 执行用时:1604 ms, 在所有 C++ 提交中击败了5.00%的用户
  • 内存消耗:230.3 MB, 在所有 C++ 提交中击败了10.55%的用户

算法复杂度 O(n*n) 双重循环

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        //* 窗口思想解决-涉及到连续的一段数据元素 -> 死窗口 O(n*n) 但容易理解
        //* 因为要求不重复 ->集合

        size_t size = s.size();
        unordered_set<char> windows;//* 最终结果,最长的子串窗口

        for (size_t i = 0; i < size; i++) {//* i指向当前需要处理的字符串的开始
            unordered_set<char> temp;//* 临时用于比较windows的大小的窗口
            temp.insert(s[i]);//* 添加到临时的窗口
            //* 看当前情况下 最大的窗口多大
            //* 如果大于初始窗口的size,那么窗口替换成最大的窗口
            //* 如果小于等于,则不进行操作
            int j = i + 1;//* 下一个元素
            while (j < size) {
                if (!temp.insert(s[j]).second){
                    break;//* 插入不了 说明重复,跳出循环
                }
                else {
                    j++;//* 如果能够插入,则判断下一个元素是否重复
                }
            }
            //* 比较
            if (windows.size() < temp.size()) {
                windows.clear();
                windows = temp;
                temp.clear();
            }
        }
        return windows.size();
    }
};

解法2 采用滑动窗口 - 参考官方解法

  • 执行用时:56 ms, 在所有 C++ 提交中击败了40.26%的用户
  • 内存消耗:11 MB, 在所有 C++ 提交中击败了43.22%的用户

算法复杂度 O(n) 只需遍历一遍即可

class Solution2 {
public:
    int lengthOfLongestSubstring(string s) {
        //* 让窗口滑动起来
        int size = s.size();
        unordered_set<char> windows;
        int result = 0;
        int wind_right = -1;//* 下一个元素
        for (int i = 0; i < size; i++) {//* i指向当前需要处理的字符串的开始
            if (i != 0) {
                //* 因为是要从下一个字符开始,所以要移除已有窗口的开始字符
                windows.erase(s[i - 1]);//* 相当于窗口向右滑动了一格
            }
            //* 滑动了窗口 => 新窗口
            //* 判断右边界的下个字符是否在窗口内,如果在,则增大窗口即右边界向右扩大一个
            //* 否则说明此时有重复,窗口停止扩张
            while (wind_right+1 < size && !windows.count(s[wind_right+1])) {
                windows.insert(s[wind_right+1]);
                wind_right++;
            }

            //* 每次进行比较窗口尺寸和之前的哪个大
            result = max(result, wind_right + 1 - i);
        }
        return result;
    }
};

:triangular_flag_on_post: TODO

  • :question: 解法2的算法分析,为啥就直接O(n)了