剑指offer 学习笔记 最长不含重复字符的子字符串
面试题48:最长不含重复字符的子字符串。请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符只包含’a’~'z’的字符。如在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4。
我们不难找出字符串的所有子字符串,然后判断每个子字符串中是否包含重复的字符,这种蛮力法的唯一缺点就是效率,一个长为n的字符串中有O(n²)个子字符串,并且需要O(n)的时间判断子字符串中是否包含重复字符,该解法的总时间复杂度是O(n²)。
动态规划解法:首先定义函数f(i)表示以第i个字符为结尾的不包含重复字符的子字符串的最长长度。我们从左到右逐一扫描字符串中的每个字符,因此当我们计算以第i个字符为结尾的不包含重复字符的子字符串的最长长度f(i)时,此时我们已经知道f(i-1)了。
如果第i个字符之前没有出现过,那么f(i)=f(i-1)+1,如在串"arabcacfr"中,显然f(0)=1,在计算f(1)时,下标为1的字符’r’之前没有出现过,因此f(1)=f(0)+1=2。
如果第i个字符之前已经出现过,我们需要先计算第i个字符和它上次出现在字符串中的位置的距离,记为d,接着分两种情形:一是d小于等于f(i-1),此时第i个字符上次出现在f(i-1)对应的最长字串之中,因此,f(i)=d,同时这也意味着在第i个字符出现两次所夹的子串中再也没有其他重复字符了。以上例分析,我们计算f(2)时,'a’已经在前面出现过,且d为2,d<=f(2-1)=f(1)=2,因此,f(2)=2,对应的最长不含重复字符的子串是"ra";二是d>f(i-1),说明此时第i个字符上次出现在f(i-1)对应的最长不含重复字符的子串之前,因此仍然有f(i)=f(i-1)+1:
#include <iostream>
#include <string>
using namespace std;
int LongestSubstringWithoutDuplication(const string& s) {
int currLength = 0, maxLength = 0;
int* pos = new int[26](); // 创建动态数组并值初始化元素为0,存储的是字符上次出现的位置
for (int i = 0; i < 26; ++i) {
pos[i] = -1; // -1说明上次没出现过
}
for (int i = 0; i < s.size(); ++i) {
int p = pos[s[i] - 'a'];
if (p == -1 || i - p > currLength) { // 如下标为i的字符没出现过或出现过但d>current
++currLength;
if (currLength > maxLength) { // 判断正常增加是否破纪录
maxLength = currLength;
}
} else { // 否则应该更新curr为d,这样会使curr变小
currLength = i - p;
}
pos[s[i] - 'a'] = i;
}
delete[] pos;
return maxLength;
}
int main() {
cout << LongestSubstringWithoutDuplication("arabcacfr") << endl;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)