题目描述:
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
考察点:
滑动窗口,动态规划,哈希
解题思路:
①滑动窗口:
当前下标的元素在滑动窗口中如果没有出现,就将当前元素插入到滑动窗口中,窗口变大。
如果当前元素在窗口里面出现过,计数不为0,表示窗口内已经有这个元素了,就需要将窗口左边的下标往右移动一个。
再次进入循环,依旧看当前元素在滑动窗口内的计数,从而根据计数决定是扩大窗口,还是将左边的窗口值继续往右移动。
②动态规划+哈希表:
状态定义:
动态规划列表dp,dp[fast]表示到fast下标为止,不重复的字符个数,
如果到此为止没有重复的:dp[fast]=dp[fast-1]+1,
如果有重复的,dp[fast]=当前的新的不重复字符串长度;
转移方程:
假设右边界为fast,左边界为slow。
①slow=-1,表示没有没有重复字符,dp[fast]=dp[fast-1]+1,最大不重复字符串长度加一
②dp[fast]<fast-slow,表示slow所在下标的字符并没有出现在当前计数范围内,在当前计数范围的左边,因此当前范围内仍没有出现重复的字符,所以dp[fast]=dp[fast]+1,最大不重复字符串长度加一
③dp[fast]>fast-slow,表示slow此时所在的下标对应的字符已经出现到有效计数范围中了,导致右边界fast-左边界slow比上一次还要小,所以dp[fast]=fast-slow,最大计数改变
结合上面三条,总结出转移方程为:
所以将哈希表和动态规划的思路结合起来如下:
遍历字符串s。
如果出现新的字符没有在哈希表中,就将这个元素插入到哈希表中。
如果遍历到的当前这个元素在哈希表中已经存在了,就更新这个元素在哈希表中的下标,将原来这个元素的换标换成当前这个元素的下标,比如:原来在哈希表中a元素的下标为0,现在遍历到字符串中有重复的字符a,其下标为3,所以将0换为3。
对于有效元素的长度,在哈希表中使用动态规划:
定义两个下标,fast,slow
fast先便利字符串,当出现和当前元素重复的字符时,slow变成第一次出现这个字符的下标,而fast此时在第二次出现这个字符的位置,记录两者之差:tmp=fast-slow
如果tmp<fast-slow,表示此时的slow没有在当前字符计数范围内,结合下面前三块图,即就是slow所在下标并没有在需要计算不重复区间中,因此有效长度在原来基础上+1;
如果tmp>=fast-slow,表示此时的slow已经移动到有效计数区间范围内部,出现了重复元素,结合下图第四块。因此有效长度改变为fast-slow。
ret表示最终返回的最大的不重复字符串长度。
完整代码:
①滑动窗口(C++):
//滑动窗口
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
int left=0;
int right=0;
int res=0;
set<char>sliding_window;
while(left<=right&&right<s.size())
{
//如果窗口范围内没有重复的,将右边的窗口右移
if(!sliding_window.count(s[right]))//表示当前右边窗口的内容在这个窗口里没有出现,计数为0,然后取反加进去为真将这个加进窗口
{
sliding_window.insert(s[right]);
right++;
}
//否则左边的窗口向右移动
else
{
res=max<int>(res,sliding_window.size());//这里max后面需要加上<int>,我认为是由于sliding_window.size()前面没有定义类型,所以需要强转一下
sliding_window.erase(s[left]);
left++;
}
}
return max<int>(res,sliding_window.size());
}
};
②动态规划+哈希表(java):
//动态规划和哈希表的方法
class Solution {
public int lengthOfLongestSubstring(String s) {
//先创建一个哈希表
Map<Character,Integer> dic=new HashMap<>();
int tmp=0;//获取两个重复元素之间的差值
int ret=0;//获取返回的最长元素个数
for(int i=0;i<s.length();i++)
{
int j=dic.getOrDefault(s.charAt(i),-1);//获取指定元素在哈希表中的下标,如果没有就返回-1.
//更新哈希表的元素,如果有重复的就进行覆盖,如果没有重复的就将元素添加进哈希表中
dic.put(s.charAt(i),i);
tmp=i-j>tmp?tmp+1:i-j;
ret=Math.max(ret,tmp);
}
return ret;
}
}