题目分析:[[EVD]] - 剑指 Offer 48. 最长不含重复字符的子字符串https://leetcode-cn.com/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/
简单描述:
- 请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
限制🚫
- s.length <= 40000
- 字符的ASCII码范围0~127
示例:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解题思路:
思路:
- #动态规划DP
- dp操作
- 只有一个决策,取不取当前字符,使用dp[i]一维数组
- dp[i]:以s[i]为结尾的 “最长不重复子字符串” 的长度
- 状态转移方程,⚠️判断该子串中是否存在重复字符s[i]=s[j] (i为最靠近j的字符下标)
- dp[j] = dp[j-1] < j-i ? dp[j-1]+1 : j-i;
"pwwkew"
3 "wke"
若s[j]=s[i]=w,则i=2,j=5;
- dp[j] = dp[j-1] < j-i ? dp[j-1]+1 : j-i;
- 空间优化的思路
- 双辅助变量,res维持更新max(dp数组),tmp维护前一个节点(因为dp[i]只和前一个节点变动值有关)
- 计算与s[j]重复字符s[i]的索引i #哈希表 #滑动窗口 #双指针
- 只有一个决策,取不取当前字符,使用dp[i]一维数组
效率:
- 时间复杂度
- 空间复杂度
代码:
- 1.哈希表+dp双辅助变量res、tmp
class Solution
{
public:
/*哈希表 + dp双辅助变量*/
int lengthOfLongestSubstring(string s)
{
int res = 0, tmp = 0;
unordered_map<char, int> map;
for (int j = 0; j < s.size(); j++)
{
int i = map.find(s[j]) != map.end() ? map.find(s[j])->second : -1;
map[s[j]] = j;
tmp = tmp < j - i ? tmp + 1 : j - i; //等价于dp[j] = dp[j-1] < j-i ? dp[j-1]+1 : j-i;
res = max(res, tmp); //等价于max(dp数组)
}
return res;
}
};
- 2.哈希表+双指针
class Solution
{
public:
/*哈希表 + 双指针*/
int lengthOfLongestSubstring(string s)
{
int res = 0, i = -1;
int d[128 + 5]; //字符的ASCII码范围0~127,d[s[j]] = i(最靠近j的相同字符i下标);
memset(d, -1, sizeof(d));
for (int j = 0; j < s.size(); j++)
{
if (d[s[j]] != -1)
i = max(i, d[s[j]]); // 更新i为最靠近j的相同字符下标
d[s[j]] = j;
res = max(res, j - i);
}
return res;
}
};