求最长无重复字符的substring的长度

本文深入探讨了使用Java解决字符串处理问题,具体聚焦于寻找给定字符串中最长无重复字符子串的方法。通过巧妙地利用布尔数组和整型数组来跟踪字符的出现情况和位置,实现了一种高效的时间复杂度解决方案。

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

public class Solution {
    public int lengthOfLongestSubstring(String s) {
        // Note: The Solution object is instantiated only once and is reused by each test case.
        int length = s.length();
        int begin=0,end=0,maxLength=0,temp=0;//begin和end是所求substring的头尾位置
	/*
	 * 计算机中ASCII码所能表示的字符个数是256
	 * 该数组的下标是每个字符对应的ASCII码
	*/
        boolean[] isExist = new boolean[256];//是否存在该字符的boolean数组
        int[] position = new int[256];//字符的位置
        
        for(int i = 0;i<length;i++){
            char c = s.charAt(i);
            end = i;
            if(isExist[c]){
                /*
                * 如果存在该字符,则计算maxLength,并且截去该字符上一次出现位置之前的字符(boolean置为false)
                * 重新确定begin
                */
                temp = maxLength;//存储上一次的maxLength
                maxLength = end - begin;
                if(maxLength<temp){
                    maxLength = temp;
                }
                for(int j = begin;j<position[c]+1;j++){
                    char d = s.charAt(j);
                    isExist[d] = false;
                }
                begin = position[c]+1;
            }
	        isExist[c]=true;
            position[c]=i;
    	    /*
    	    *如果是最后一个字符,则直接计算出maxLength
    	    */
    	    if(end == length-1){
            	temp = maxLength;
            	maxLength = end-begin+1;
            	if(maxLength<temp){
            	    maxLength = temp;
            	}
            }
        }
        return maxLength;
    }
}

<think>好的,我现在要解决“最长无重复字符的子串”这个问题。这个问题是常见的算法题,我需要仔细思考如何高效地找到解决方案。 首先,我要明确问题要。题目是给定一个字符串,找出其中不含有重复字符的最长子串的长度。例如,输入"abcabcbb",正确输出应该是3,因为最长子串是"abc"。另一个例子,"bbbbb"的最长子串是"b",长度为1。还有像"pwwkew"的情况,最长子串是"wke"或"kew",长度3。 接下来,我需要考虑不同的解决方法。最直接的可能是暴力法,遍历所有可能的子串,检查是否有重复字符,记录最长的那个。但这种方法的时间复杂度会是O(n³),因为两层循环遍历子串,加上检查重复的哈希集合操作。这样的复杂度对于长字符串来说效率很低,显然需要优化。 于是,我想到滑动窗口(Sliding Window)的方法。滑动窗口通常用于处理子串或子数组问题,可以在O(n)的时间复杂度内解决问题。其核心思想是维护一个窗口,通过移动左右指针来调整窗口的大小,确保窗口内没有重复字符。 具体来说,可以定义一个左指针left和右指针right,初始时都指向字符串的起始位置。然后,右指针不断向右移动,扩大窗口。同时,用一个哈希集合(HashSet)来记录当前窗口中的字符,用于快速判断是否有重复。当右指针指向的字符已经存在于集合中时,说明出现了重复,此时需要移动左指针,直到重复的字符被移出窗口,同时更新哈希集合。在这个过程中,记录窗口的最大长度。 举个例子,假设字符串是"abcabcbb"。初始时left=0,right=0,集合为空。right向右移动,依次加入a、b、c,此时窗口长度3。当right移动到3(字符a)时,发现a已经在集合中,于是需要移动left到1的位置,移出原left位置的a。继续移动right,直到再次遇到重复字符,重复这个过程,保持记录最大窗口长度。 不过,这个方法在遇到重复字符时可能需要逐步移动左指针,例如在例子"abba"中,当right移动到第二个b时,left需要移动到max(left, 原b的位置+1)。这里需要记录每个字符最后出现的位置,而不仅仅是检查是否存在。这时候,可能更适合使用哈希表(HashMap)来存储每个字符的最新索引,这样当遇到重复时,可以直接将left跳到max(left, 重复字符上次位置+1),从而避免逐个移动左指针,减少时间复杂度。 例如,使用哈希表保存字符到索引的映射。当右指针遍历到字符c时,检查c是否在哈希表中,并且其索引是否大于等于当前left。如果是,则更新left为该字符上次出现的位置+1。然后更新c的索引到当前right,并计算当前窗口长度right-left+1,更新最大值。 这样的方法可以将时间复杂度降到O(n),因为每个字符最多被访问两次(一次被右指针,一次被左指针),空间复杂度是O(min(m, n)),其中m是字符集大小(比如ASCII字符集是128或256),n是字符串长度。 接下来,我需要考虑边界情况。比如空字符串的情况,应该返回0。所有字符都相同的情况,如"bbbb",应该返回1。还有像"abba"这样的例子,当right到第二个b时,left跳到2;但到第二个a时,原a的位置是0,此时left已经是2,所以不需要改变,这样窗口长度是right(3)-left(2)+1=2,但正确的最长长度应该是2("ab"或"bb"或"ba"?不,实际上最长应该是"ab"或者"ab"后面的"b"或者"a",可能哪里出错了。或者原例子"abba"的最长无重复子串是"ab"和"ba",长度2。这时候算法是否正确?当处理第二个a时,原a的位置是0,此时left是2,所以max(left, 0+1)=2,更新a的位置为3,此时窗口是3-2+1=2,正确。是的,这样处理是对的。 现在,我需要具体实现这个算法。大致步骤如下: 1. 初始化哈希表(字符到索引的映射),max_length=0,left=0。 2. 遍历字符串,右指针从0到n-1: a. 如果当前字符在哈希表中且其值>=left,则移动left到该字符的位置+1。 b. 更新当前字符的索引到哈希表中。 c. 计算当前窗口长度(right - left +1),更新max_length。 3. 返回max_length。 这样就能覆盖所有情况,并且处理重复字符时高效地调整左指针的位置。 接下来,测试几个例子: 例子1:"abcabcbb" 过程: - right=0,字符a,不在哈希表,添加,窗口长度1,max=1。 - right=1,字符b,不在,添加,窗口长度2,max=2。 - right=2,字符c,不在,添加,窗口长度3,max=3。 - right=3,字符a,存在且位置0 >= left(0)。所以left=0+1=1。更新a的位置为3。窗口长度3-1+1=3,max保持3。 - right=4,字符b,存在,之前位置1 >= left(1)。left=1+1=2。更新b的位置4。窗口长度4-2+1=3。 - right=5,字符c,存在,之前位置2 >= left(2). left=2+1=3。更新c的位置5。窗口长度5-3+1=3. - right=6,字符b,存在,之前位置4 >= left(3). left=4+1=5。窗口长度6-5+1=2. - right=7,字符b,存在,之前位置5 >= left(5). left=5+1=6. 窗口长度7-6+1=2. 最终max是3,正确。 例子2:"bbbbb" 每个字符b,每次遇到时,哈希表中存在,且位置>=left。所以每次left移动到i+1,比如right=0,left=0,发现b存在,则left=0+1=1。窗口长度0-1+1=0?或者可能我哪里弄错了。或者可能初始时哈希表是空的,所以第一个b加入哈希表,窗口长度1。第二个b时,发现存在,且位置0 >= left=0,所以left=0+1=1。窗口长度1-1+1=1。之后每个步骤都是left=right+1,窗口长度保持1。最终max是1,正确。 例子3:"pwwkew" right=0,p不在,窗口1,max=1. right=1,w不在,窗口2,max=2. right=2,w存在,之前位置1 >= left=0。left=1+1=2. 更新w的位置2.窗口长度2-2+1=1. right=3,k不在,窗口长度2,max=2. right=4,e不在,窗口长度3,max=3. right=5,w存在,之前位置2 < left=2吗?此时,当前哈希表中w的位置是2。此时left是2,所以w的位置2 >= left=2。所以left=2+1=3. 更新w的位置5.窗口长度5-3+1=3. max保持3. 最终max是3,正确。 例子4:"abba" right=0,a加入,窗口1,max=1. right=1,b加入,窗口2,max=2. right=2,b存在,位置1 >= left=0 → left=1+1=2. 更新b的位置2.窗口长度1(2-2+1=1),max还是2. right=3,a存在,位置0。此时,检查0是否 >= left=2 → 不是。所以不需要移动left。更新a的位置3.窗口长度3-2+1=2 → max=2. 正确,最长子串是"ab"或"bb"或"ba",长度2。 综上,该算法处理各种情况正确。现在需要将这个思路用代码实现,注意处理哈希表的更新和left的移动。</think>最长无重复字符的子串问题要找到给定字符串中不含重复字符的最长子串长度。以下是解决该问题的分步说明: --- ### **问题分析** - **目标**:找到字符串中连续且无重复字符最长子串长度。 - **示例**: - `"abcabcbb"` → 最长子串`"abc"`,长度3 - `"bbbbb"` → 最长子串`"b"`,长度1 - `"pwwkew"` → 最长子串`"wke"`或`"kew"`,长度3 --- ### **解决方法:滑动窗口 + 哈希表** 通过维护一个动态窗口,用哈希表记录字符最后一次出现的位置,确保窗口内无重复字符。 #### **步骤说明** 1. **初始化变量**: - `left = 0`:窗口左指针。 - `max_len = 0`:记录最大长度。 - `char_map = {}`:哈希表,存储字符及其最新索引。 2. **遍历字符串**(右指针`right`从0开始): - **若字符已存在且其位置≥`left`**: - 将`left`移动到重复字符的下一个位置(跳过重复)。 - **更新哈希表**:将当前字符及其位置存入。 - **计算当前窗口长度**:`right - left + 1`,更新`max_len`。 3. **返回结果**:`max_len`。 --- ### **示例演示** 以字符串`"abcabcbb"`为例: 1. `right=0`(字符`a`):`char_map={'a':0}`,窗口长度1。 2. `right=1`(字符`b`):`char_map={'a':0, 'b':1}`,窗口长度2。 3. `right=2`(字符`c`):窗口长度3,`max_len=3`。 4. `right=3`(字符`a`):`a`已存在且位置0≥`left=0`,移动`left=1`,更新`char_map['a']=3`,窗口长度3。 5. 后续步骤同理,最终得到最长长度3。 --- ### **代码实现** ```python def length_of_longest_substring(s: str) -> int: char_map = {} # 存储字符最后出现的位置 max_len = 0 left = 0 # 窗口左边界 for right in range(len(s)): current_char = s[right] # 如果字符已存在且位置≥left,移动left到重复字符的下一位 if current_char in char_map and char_map[current_char] >= left: left = char_map[current_char] + 1 # 更新字符的最新位置 char_map[current_char] = right # 计算当前窗口长度 max_len = max(max_len, right - left + 1) return max_len ``` --- ### **复杂度分析** - **时间复杂度**:O(n),每个字符被访问一次。 - **空间复杂度**:O(min(m, n)),其中m为字符集大小(如ASCII为128),n为字符串长度。 --- ### **关键点** - **滑动窗口**:通过调整左右指针动态维护无重复区间。 - **哈希表优化**:记录字符最新位置,避免重复检查。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值