前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >leetcode 3. 无重复字符的最长子串----滑动窗口篇1,双指针篇1

leetcode 3. 无重复字符的最长子串----滑动窗口篇1,双指针篇1

作者头像
大忽悠爱学习
发布2021-11-15 11:01:40
2260
发布2021-11-15 11:01:40
举报
文章被收录于专栏:c++与qt学习
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

无重复字符的最长子串题解集合


滑动窗口—双指针法

思路:

这道题主要用到思路是:滑动窗口

什么是滑动窗口?

其实就是一个队列,比如例题中的 abcabcbb,进入这个队列(窗口)为 abc 满足题目要求,当再进入 a,队列变成了 abca,这时候不满足要求。所以,我们要移动这个队列!

如何移动?

我们只要把队列的左边的元素移出就行了,直到满足题目要求!

一直维持这样的队列,找出队列出现最长的长度时候,求出解!

时间复杂度:O(n)

图解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码:

代码语言:javascript
复制
class Solution {
public:
	int lengthOfLongestSubstring(string s) 
	{
		if (s.empty()) return 0;
		int start(0), end(0), maxLength(1),len(0);
		for (; end < s.size(); end++)
		{
			char temp = s[end];
			for (int j = start; j < end; j++)
			{
				if (s[j] == temp)//当前滑动窗口出现重复字符
				{
					start = j + 1;
					//计算start指针更新后,当前滑动窗口内元素的个数,注意此时end指针指向的元素已经和滑动窗口里面任何一个元素都不重合
					//一会还需要把end指针指向的元素放入更新后的滑动窗口内,就len的长度一会还需要加一
					len = end - start;
					break;
				}
			}
			//如果当前end指针指向的元素与滑动窗口内的某个元素重复,那么start指针需要更新到新的位置,当start指针更新到新的位置后
			//我们还需要把原先没有纳入滑动窗口范围,即end指针指向的元素纳入滑动窗口范围,即len的长度要加一
			len++;
			maxLength = max(maxLength, len);
			//然后end指针再继续后移
		}
		return maxLength;
	}
};
在这里插入图片描述
在这里插入图片描述

哈希表优化

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意: 哈希容器存储的是把当前字符作为关键字,将当前字符的下标作为值,当出现重复的字符时,就把start指针移动到前面一个重复字符位置之后,然后将后一个新出现的重复字符下标覆盖原来的字符下标

代码:

代码语言:javascript
复制
class Solution {
	unordered_map<char, int> cache;
public:
	int lengthOfLongestSubstring(string s) 
	{
		if (s.empty()) return 0;
		int start(0), end(0), maxLength(1),len(0);
		for (; end < s.size(); end++)
		{
			char temp = s[end];
			//出现重复字符----注意:仅当s[start,end) 中存在s[end]时更新start
			//因为随着滑动窗口大小和位置的变化,可能某些数据原先已经存入了哈希表中,但是随着滑动窗口大小和位置的变化
			//这些数据离开了滑动窗口的范围,但是数据依然保留在哈希表内部
			//因此这里要限制必须当前元素是与滑动窗口里面的元素重复,不包括外部
			if (cache.find(temp) != cache.end()&&cache[temp] >= start)
			{
					start = cache[temp] + 1;
					len = end - start;

		    }
			cache[temp] = end;
			len++;
			maxLength = max(maxLength, len);
		}
		return maxLength;
	}
};
在这里插入图片描述
在这里插入图片描述

数组(桶)代替哈希表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

注意:这里选择ascall码做桶,数组大小为128.因为ascall的范围是0----127,数组内所有元素初始值为-1,当某个字符出现时,就将其的ascall码对应在数组中的位置值改成当前字符下标

如何判断是否出现重复元素呢?

如果利用当前字符ascall对应去数组找位置,发现该位置的值不为-1,说明之前该元素已经出现过了,需要更新其对应的下标

当然这里还有一个技巧,如果原本在滑动窗口内的元素,后来因为滑动窗口右移而脱离滑动窗口了,那么它对于的下标一定比start下标小,因为start是滑动窗口最左段的下标,可以利用此判断当前元素是与滑动窗口内元素重复还是外部

这里其实类似哈希映射,也同样要注意当前字符是与滑动窗口范围内的元素进行比较,判断是否与某个字符重复,而不是与滑动窗口外的字符进行比较

代码:

代码语言:javascript
复制
class Solution {
public:
	int lengthOfLongestSubstring(string s) 
	{
		if (s.empty()) return 0;
		int start(0), end(0), maxLength(1),len(0);
		vector<int> ascall(128, -1);
		for (; end < s.size(); end++)
		{
			char temp = s[end];
			//说明当前元素是和滑动窗口内元素产生重复
			if (ascall[temp] >= start)
			{
				start = ascall[temp] + 1;
				 len = end - start;
			}
			//更新当前产生重复元素的下标
			ascall[temp] = end;
			len++;
			maxLength = max(maxLength, len);
		}
		return maxLength;
	}
};
在这里插入图片描述
在这里插入图片描述

动态规划

1、“状态”的定义

dp[i]:从字符串s起始位置开始到i位置的最长不重复子串长度

2、推导“状态转移方程”

分两种情况:

1)第i个字符不参与到当前字符串的最长子串,有dp[i]=dp[i-1]。

2)第i个字符参与到当前字符串的最长子串,检查从第i个字符往前数dp[i-1]个字符长度的子串,若没有重复,则有dp[i]=dp[i-1]+1,若有重复,则为情况1)。

最终当前dp[i]的结果,取决于上面两种选择中结果较大者,那么显然第i个字符参与进来后得到的长度肯定比不参与得到的大.

但是能否参与进来,取决于第i个字符有没有与前面dp[i-1]个字符产生重复,如果重复了那么就只能维持dp[i-1]的结果

这里选择了第i个字符后,需要去查看当前字符i和前面dp[i-1]个字符组成的字符串中是否存在两两甚至更多重复的元素

这里可以截取出从i位置往前i-1个字符组成的字符串,然后对字符串进行排序,方便两两比较,查看是否有重复字符

在这里插入图片描述
在这里插入图片描述

代码:

代码语言:javascript
复制
	class Solution {
public:
	int lengthOfLongestSubstring(string s) 
	{
		if (s.empty()) return 0;
		vector<int> dp(s.size());
		//当i=0时,即只有一个字符的时候,那么最长不重复子串长度就是1
		dp[0] = 1;
		for (int i = 1; i < dp.size(); i++)
		{
			//判断当前字符是否与前面dp[i-1]个字符中的字符重复
			bool found = false;
			//这里需要判断从位置i起往前dp[i-1]个字符里面是否存在两两或者多个重复元素
			//截取需要判断是否有重复元素的子串,并且进行排序,方便两两比对判断是否有重复
			string currentString = s.substr(i - dp[i-1],dp[i-1] + 1);
			sort(currentString.begin(), currentString.end());
			for (int j =0; j <dp[i - 1]; j++)
			{
				if (currentString[j] == currentString[j + 1])
				{
					found = true;
					break;
				}
			}
			//产生了重复,说明要维持当前最长不重复子串长度
			if (found)
				dp[i] = dp[i - 1];
			else
				dp[i] = dp[i - 1] + 1;
		}
		return  dp[dp.size() - 1];
	}
};
在这里插入图片描述
在这里插入图片描述
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/05/28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 无重复字符的最长子串题解集合
  • 滑动窗口—双指针法
  • 哈希表优化
  • 数组(桶)代替哈希表
  • 动态规划
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档