【思考题】连续子串问题

本文探讨了一串包含正负数的数字中不同条件下的子串和问题:包括连续子串和的最大值、非连续子串和的最大值、连续子串和的绝对值最大值及最小值,并提供了具体的算法思路。

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

问题1:给出一串数字,有正数也有负数,现在要求你找出这一串数里面连续子串和最大的值为多少?
分析:这道题目是为了求解连续子串和的最大值,我们可以一遍循环就能找出解决方案,要求a[i],则首先判断a[i-1],如果a[i-1]>=0则a[i]+=a[i-1],如果a[i-1]<0则a[i]=a[i],这样一遍循环以后,我们找出a[1~n]里面最大值就是我们所需要求解的值
.
问题2:给出一串数字,有正数也有负数,现在要求你找出这一串数里面子串和(不要求连续)的最大值是多少?
分析:略微变化一下,改为不需要连续,好吧,这道题目我想的脑残了,大家纯属娱乐,如果不连续,我们直接找出所有正数相加就行了嘛,如果全是负数,找出最大的那个负数值,纠结,昨晚竟然没有想到这点儿,还把问题写到这儿,纠结~~~~
.
问题3:给出一串数字,有正数也有负数,现在要求你找出这一串数里面连续子串和的绝对值最大值是多少?(注意是绝对值)
分析:这道题目想了好久没有一下子想出来,思维定视厉害呀!和第一道题目不同的地方在于此处是要求求解绝对值,所以有时候几个负数相加取绝对值比几个正数相加的和大,所以采用问题一的策略是行不通的。所以我们可以让a[i]等于前i项和,再将a数组从小到大排序,排好序后,Max=max(abs(a[n]-a[1]),abs(a[n]),abs(a[1]));这样我们就求解出了最大值了。排好序后的a数组我们只知道它是从1到后面某一个数这一段的总和,用a[n]-a[1]代表的是这段数据可能的值最大,当然也有可能a[n],a[1]最大,所以我们要求解他们三者的最大值。感觉挺巧妙的一个方法,时间复杂度是O(nlogn),主要耗时就在排序了。
.
问题4:给出一串数字,有正数也有负数,现在要求你找出这一串数里面连续子串和的绝对值最小值是多少?(注意是绝对值)
分析:解法同问题三,稍微思考一下就明白了~~~
<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、付费专栏及课程。

余额充值