字符串系列---longest-substring-without-repeating-characters

本文介绍了一种基于滑动窗口原理求解字符串中最长无重复字符子串长度的高效算法,并通过具体示例展示了算法的实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目
Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for “abcabcbb” is “abc”, which the length is 3. For “bbbbb” the longest substring is “b”, with the length of 1.

实现
“滑动窗口” 原理:比方说 abcabccc 当你右边扫描到abca的时候你得把第一个a删掉得到bca,然后”窗口”继续向右滑动,每当加到一个新char的时候,左边检查有无重复的char, 然后如果没有重复的就正常添加,有重复的话就左边扔掉一部分(从最左到重复char这段扔掉),在这个过程中记录最大窗口长度

/*
     * 利用滑动窗口原理;
     * map<Character,Integer>存放字符对应的位置;
     * 每遍历一个字符,都计算窗口大小:
     *   计算左边界:map中是否存在该字符?存在:位置+1 ;不存在:0;
     *   窗口大小:该字符位置-左边界+1;
     *   比较最大窗口和当前计算的窗口;
     */
    public int lengthOfLongestSubstring(String s) {
        if(s==null ||s.length()==0){
            return 0;
        }
        int max=0;
        int leftBound=0;
        Map<Character,Integer> map=new HashMap<Character,Integer>();
        for(int i=0;i<s.length();i++){
            char c=s.charAt(i);

            //每次出现重复字符,则leftBound变为第一个重复字符的下一个;
            leftBound=Math.max(leftBound,map.containsKey(c)?map.get(c)+1:0);
            max=Math.max(max, i-leftBound+1);
            map.put(c, i);
        }
        return max;
    }
<think>首先,用户的问题是关于“最长子区间问题”的算法解法。用户说:“我想寻找关于最长子区间问题的解决方案或算法请问最长子区间问题算法解法”。结合上下文,用户可能指的是“无重复字符的最长子串”问题,因为在之前的引用中多次提到这个,比如引用[2]、[3]、[4]、[5]都讨论了这个问题。从系统指令中,我需要:-使用$...$用于行内数学表达式。-使用$$...$$用于独立公式。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在回答中引用的段落末尾自然地添加引用标识,例如[^1]。-回答结构清晰,帮助用户逐步解决问题,尽量保证真实可靠。用户提到的引用:-[^1]:关于算法如快速排序、动态规划等。-[^2]:关于无重复字符的最长子串的暴力解法和滑动窗口优化。-[^3]:LeetCode3无重复字符的最长子串问题描述和C#解法。-[^4]:滑动窗口解法代码。-[^5]:滑动窗口思想解释。用户的问题焦点是“最长子区间问题”,但具体上下文表明它可能指“无重复字符的最长子串”。我应该确认并基于此回答。核心算法是滑动窗口(SlidingWindow)算法,因为它高效地解决了这个问题。结构化回答:1.**介绍问题**:解释什么是“无重复字符的最长子串”问题。2.**描述算法**:逐步解释滑动窗口算法。3.**提供代码示例**:用伪代码或实际语言展示实现。4.**分析性能**:讨论时间复杂度和空间复杂度。5.**生成相关问题**:根据指令,在最后添加相关问题。确保使用中文。数学表达式:如果需要,使用$...$。例如,在讨论复杂度时,$O(n)$。引用标识:当引用站内内容时添加[^n]。回答结构:-开头:确认问题。-主体:逐步解释解法。-结尾:生成相关问题。现在,构建内容。**步骤1:介绍问题**用户说“最长子区间问题”,但引用都是关于“无重复字符的最长子串”。所以,我应该指出这一点。例如:在算法领域,"最长子区间问题"常指"无重复字符的最长子串"问题,即在给定字符串中找到最长的不包含重复字符的子串[^3]。**步骤2:解释滑动窗口算法**-基本思想:使用两个指针(左指针和右指针)定义一个窗口,表示当前子串。-使用一个数据结构(如哈希表或数组)来存储字符的出现次数。-移动右指针扩展窗口,如果遇到重复字符,移动左指针缩小窗口。-维护最大长度。基于引用[4]和[5]。**步骤3:代码示例**提供代码。既然引用中有C++和Java,我可以选择一个或写伪代码。例如,用Python实现滑动窗口。**步骤4:性能分析**时间复杂度:$O(n)$,因为每个字符最多被访问两次(一次进窗口,一次出窗口)。空间复杂度:$O(1)$,如果使用固定大小的数组(ASCII字符集)。**步骤5:生成相关问题**在最后添加3-5个相关问题。现在,确保LaTeX:-行内:$O(n)$-独立:如果有公式,但这里可能不需要独立公式。引用:-当提到问题描述时引用[^3]。-当提到滑动窗口优化时引用[^2]或[^4]。-当提到单调性和指针移动时引用[^5]。最终回答框架:1.问题定义2.算法步骤3.代码实现(例如Python)4.复杂度分析5.相关问题</think>### 最长子区间问题:无重复字符的最长子串算法解法 在算法领域中,"最长子区间问题"通常指代**无重复字符的最长子串**问题(Longest Substring Without Repeating Characters),这是一个经典的字符串处理问题。给定一个字符串 $s$,目标是找到其中**不包含重复字符的最长连续子串(子区间)**,并返回其长度。例如: - 输入 $s = \text{"abcabcbb"}$,输出 $3$(子串 $\text{"abc"}$)[^3]。 - 输入 $s = \text{"bbbbb"}$,输出 $1$(子串 $\text{"b"}$)[^3]。 这个问题在 LeetCode(题号 3)和华为 OD 等算法考试中常见,核心解法基于**滑动窗口算法**(Sliding Window)。该算法利用双指针动态调整窗口大小,高效处理子区间问题,时间复杂度为 $O(n)$,空间复杂度为 $O(1)$(假设字符集大小固定)。下面我将逐步解释其原理和实现。 --- ### 一、滑动窗口算法详解 滑动窗口算法通过两个指针(左指针 `left` 和右指针 `right`)定义一个"窗口",表示当前子串。窗口内字符无重复时扩展右指针,遇到重复时收缩左指针。同时,使用一个数据结构(如哈希表或数组)记录字符出现频次,确保高效检查重复。 #### 算法步骤: 1. **初始化**: - 左指针 `left = 0`,右指针 `right = 0`。 - 最大长度 `max_len = 0`。 - 频次数组 `freq`(大小 128,覆盖 ASCII 字符集),初始化为 0。 2. **移动右指针(扩展窗口)**: - 循环 `while right < len(s)`: - 将 `s[right]` 的频次加 1:`freq[s[right]]++`。 - 如果 `freq[s[right]] > 1`(表示重复),则进入内层循环收缩左指针。 - 更新最大长度:`max_len = max(max_len, right - left + 1)`。 - 右指针右移:`right++`。 3. **移动左指针(收缩窗口)**: - 内层循环 `while freq[s[right]] > 1`: - 将 `s[left]` 的频次减 1:`freq[s[left]]--`。 - 左指针右移:`left++`(直到重复字符被移除)。 4. **终止条件**:当 `right` 遍历完字符串时结束。 此方法基于**单调性**:右指针只前进不退,左指针只在必要时前进,确保每个字符最多被访问两次[^5]。时间复杂度为 $O(n)$($n$ 是字符串长度),空间复杂度为 $O(1)$(固定大小数组)。 #### 为什么高效? - **暴力解法**(枚举所有子串)需要 $O(n^2)$ 时间,而滑动窗口优化为 $O(n)$[^2]。 - 频次数组替代哈希表,减少开销[^4]。 --- ### 二、代码实现(Python 示例) 以下是滑动窗口算法的 Python 实现,代码简洁且符合算法思想: ```python def lengthOfLongestSubstring(s: str) -> int: left = 0 # 左指针 max_len = 0 # 最大长度 freq = [0] * 128 # ASCII 频次数组 for right in range(len(s)): # 右指针遍历 char_index = ord(s[right]) # 字符转 ASCII 索引 freq[char_index] += 1 # 进窗口 # 收缩窗口:当 s[right] 出现重复时 while freq[char_index] > 1: left_char = ord(s[left]) freq[left_char] -= 1 # 出窗口 left += 1 # 左指针右移 # 更新最大长度 max_len = max(max_len, right - left + 1) return max_len ``` #### 示例测试: - 输入 `s = "pwwkew"`,输出 `3`(子串 `"wke"`)[^3]。 - 输入 `s = "abcabcbb"`,输出 `3`。 代码关键点: - 使用数组 `freq` 替代哈希表,提升效率[^4]。 - 内层 `while` 循环确保窗口内无重复[^5]。 --- ### 三、性能与应用场景 - **时间复杂度**:$O(n)$,每个字符最多被处理两次(进/出窗口)[^5]。 - **空间复杂度**:$O(1)$(固定大小数组)[^4]。 - **应用场景**: - 字符串处理问题(如 DNA 序列分析)。 - 算法竞赛和面试题(如 LeetCode、华为 OD 考试)[^1]。 - 数据流中实时检测重复模式。 此解法已被广泛验证,是解决无重复字符最长子串的标准方法[^3][^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值