学习笔记35——最长不含重复子串的子字符串(两种方法)

题目:请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。假设字符串中只包含从’a’到’z’的字符。例如,在字符串"arabcacfr"中,最长的不含重复字符的子字符串是"acfr",长度为4。
思路:
方法一:暴力法,时间复杂度为O(n3)
一个长度为n的字符串有O(n2)个子字符串,我们找出所有的子字符串,然后需要O(n)判断每个子字符串中是否包含重复的字符,总的时间复杂度为O(n3)
方法二:动态规划法,时间复杂度为O(n)
首先定义函数f(i)表示以第i个字符为结尾的不包含重复字符的子字符串的最长长度,接着从左到右逐一扫描字符串中的每个字符。因为当我们计算以第i个字符为结尾的不包含重复字符的子字符串的最长长度f(i)时,我们已经知道f(i-1)了。具体分析如下:

扫描到第i个字符f(i)
第i个字符之前没出现过f(i)=f(i-1)+1
第i个字符之前出现过,d>f(i-1)f(i)=f(i-1)+1
第i个字符之前出现过,d<=f(i-1)f(i)=d

两种方法的核心代码如下:

//方法1:暴力法,时间复杂度为O(n3)
bool hasDuplication(const string& str, int position[]);
int longestSubstringWithoutDuplication1(const string& str){
	int longest = 0;
	int* position = new int[26];
	//一个长度为n的字符串有O(n*n)个子字符串
	for(int start = 0; start < str.length(); start++){
		for(int end = start; end < str.length(); end++){
			int count = end - start + 1;
			const string& substring = str.substr(start, count);
			if(!hasDuplication(substring, position)){ //如果substring中不包含重复字符
				if(count > longest)
					longest = count;
			}
			else
				break;
		}
	}
	delete[] position;
	return longest; //返回最长子字符串的长度
}

//检测子字符串中是否包含重复字符,如果包含则返回true,如果不包含返回false
bool hasDuplication(const string& str, int position[]){
	//position数组初始化为-1,表示每个元素对应的字符在字符串中还没有出现过
	for(int i = 0; i < 26; i++)
		position[i] = -1;

	for(int i = 0; i < str.length(); i++){
		int indexInPosition = str[i] - 'a';
		if(position[indexInPosition] >= 0) //当前字符在前面已出现过
			return true;
		position[indexInPosition] = indexInPosition;		
	}
	return false;
}

//方法2:动态规划法,时间复杂度为O(n)
int longestSubstringWithoutDuplication2(const string& str){
	int curLength = 0;
	int maxLength = 0;

	int* position = new int[26];
	//position数组初始化为-1,表示每个元素对应的字符在字符串中还没有出现过
	for(int i = 0; i < 26; i++)
		position[i] = -1;

	for(int i = 0; i < str.length(); i++){
		int prevIndex = position[str[i] - 'a']; //将第i个字符上次出现在字符串中的位置存入prevIndex中
		//该字符从未出现过 或 第i个字符和它上次出现在字符串中的位置的距离(i - prevIndex)大于curLength,即d>f(i-1)
		//意味着第i个字符上次出现在f(i-1)对应的最长子字符串之前,因此仍然有f(i)=f(i-1)+1
		if(prevIndex < 0 || i - prevIndex > curLength) 
			curLength++; //令f(i)=f(i-1)+1
		else{ //d<=f(i-1),此时第i个字符上次出现在f(i-1)对应的最长子字符串中,因此f(i)=d
			if(curLength > maxLength) 
				maxLength = curLength; 

			curLength = i - prevIndex; //令f(i)=d
		}
		position[str[i] - 'a'] = i; //position用来存储每个字符最近一次出现在字符串中位置的下标
	}
	if(curLength > maxLength)
		maxLength = curLength;

	delete[] position;
	return maxLength;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值