【剑指offer】面试题48:最长不含重复字符的子字符串

13 篇文章 0 订阅
13 篇文章 0 订阅

题目描述
从字符串中找出一个最长的不包含重复字符的子字符串,计算这个字符串长度。字符串只包含a-z字母。如“arabcacfr”,最长的包含重复子字符串是“acfr”,长度是4。

  • 解题思路:
    已知第i-1个字符的最长子字符串长度,根据第i个字符是什么,总结规律,得出第i个字符的最长子字符串长度。
  • 几个注意点:
    1.递归用循环代替减少重复计算。
  • 解题步骤:
    先推递归式:
    一开始没看懂是因为看错了f(i)的定义。强调下f(i)是以第i个字符为结尾的不包含重复字符的子字符串的最长长度。
    • 如果第i个字符没出现过,f(i)=f(i-1)+1
    • 如果第i个字符出现过,得到上次出现的位置的距离d
      • 如果d小于等于f(i-1),说明上次出现的位置在f(i-1)那个子字符串之中,调整f(i)=d
      • 如果d大于f(i-1),说明上次出现的位置在f(i-1)那个子字符串之前,f(i)=f(i-1)+1

获取上次出现过的字符的位置,用一个数组position来维护,实时更新数组状态。

但我们要求的不是f(i),我们要维护一个maxLength变量,用来更新递归/循环过程中的最大值,也就是我们要求的答案。
如果没遇到出现过的字符,没必要更新maxLength,在循环结束后最后更新maxLength=f(i)就行。
如果遇到过的字符,并且要修改了f(i)=d之前,一定要更新maxLength,因为修改后的f(i)可能不是最大的长度了。
最后返回maxLength,即为最后答案。

【考点】递归 动态规划

class Solution {
public:
	int longestSubstringWithoutDuplication(const string& str) {
		int curLength = 0;	// f(i)
		int maxLength = 0;	// 答案

		int* position = new int[26];
		for (int i = 0; i < 26; ++i)
			position[i] = -1;

		for (int i = 0; i < str.length(); ++i)
		{
			int prevIndex = position[str[i] - 'a'];
			int d = i - prevIndex;
			// 字符没出现过 或者 字符出现过但d > f(i-1)
			if (prevIndex < 0 || d > curLength)
				// f(i) = f(i-1)+1
				++curLength;
			else // 字符出现过但d <= f(i-1)
			{
				// 更新答案
				if (curLength > maxLength)
					maxLength = curLength;
				// f(i) = d
				curLength = d;
			}
			position[str[i] - 'a'] = i;
		}
		// 更新答案
		if (curLength > maxLength)
			maxLength = curLength;

		delete[] position;
		return maxLength;
	}
};
int main(){
	Solution obj;
	string str= "arabcacfr";
	int res = obj.longestSubstringWithoutDuplication(str);
	cout << res << endl;
	return 0;
}

Output
4

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值