力扣dp题
思路
已知字符串S,求其最长的不含重复字符的子串,最优解问题想到动态规划:
- 设 dp[ j ] 记录以 s[ j ] 字符为结尾的最长不含重复字符子串的长度。
- 设 s[i] 为在 s[j] 左边出现的距离最近的相同字符 (i<j)。
- 当我们遍历计算 dp 至 dp[j] 时,如果 s[j] 左边没有与之相同的字符 s[i] ,则 dp[j]=dp[j-1]+1 ;
- 如果 s[j] 左边有 s[i] 与之相同,则需要判断前一个状态 dp[j-1] 的字符串长度与i的位置关系:
- 若 dp[j-1]<j-i ,说明 s[i 在 dp[j-1] 所表示的子串之外,对 dp[j] 结果不造成影响,此时 dp[j]=dp[j-1]+1 ;
- 若 dp[j-1]>=j-i ,说明 s[i] 正好落在了 dp[j-1] 所表示的子串内,此时 dp[j] 的值应更新为 s[i] 至 s[j] 之间的长度,即 dp[j]=j-i ;
题解代码+超级详细注释
class Solution {
public:
int lengthOfLongestSubstring(string s) {
int n=s.size();
if(n==0)return 0;//空字符串判断
vector<int> dp(n,0);//dp[j]用来表示以s[j]为结尾的最长不含重复字符的子字符串的长度
dp[0]=1;//初始化,单字节字符串一定无重复
for(int j=1;j<n;++j){
dp[j]=dp[j-1]+1;//在左边没有与s[j]重复字符的情况下,dp[j]=dp[j-1]+1;
for(int i=j-1;i>=0;--i){//从j-1位置开始,自右向左遍历查看是否有重复字符
if(s[i]==s[j]&&dp[j-1]>=j-i){
dp[j]=j-i;//当相同字符s[i]的位置处于dp[j-1]的长度范围内,则dp[j]的值应更新为j-i,如果在dp[j-1]的长度之外,则对dp[j]无影响
break;//找到距离最近的重复字符,判断完毕后就应立即跳出循环
}
}
}
sort(dp.begin(),dp.end());
return dp[n-1];
}
};