【Z函数 KMP扩展】3031. 将单词恢复初始状态所需的最短时间 II|2277

本文涉及知识点

KMP扩展 Z函数 较难理解的字符串查找算法KMP

LeetCode3031. 将单词恢复初始状态所需的最短时间 II

给你一个下标从 0 开始的字符串 word 和一个整数 k 。
在每一秒,你必须执行以下操作:
移除 word 的前 k 个字符。
在 word 的末尾添加 k 个任意字符。
注意 添加的字符不必和移除的字符相同。但是,必须在每一秒钟都执行 两种 操作。
返回将 word 恢复到其 初始 状态所需的 最短 时间(该时间必须大于零)。
示例 1:
输入:word = “abacaba”, k = 3
输出:2
解释:
第 1 秒,移除 word 的前缀 “aba”,并在末尾添加 “bac” 。因此,word 变为 “cababac”。
第 2 秒,移除 word 的前缀 “cab”,并在末尾添加 “aba” 。因此,word 变为 “abacaba” 并恢复到始状态。
可以证明,2 秒是 word 恢复到其初始状态所需的最短时间。
示例 2:
输入:word = “abacaba”, k = 4
输出:1
解释:
第 1 秒,移除 word 的前缀 “abac”,并在末尾添加 “caba” 。因此,word 变为 “abacaba” 并恢复到初始状态。
可以证明,1 秒是 word 恢复到其初始状态所需的最短时间。
示例 3:
输入:word = “abcbabcd”, k = 2
输出:4
解释:
每一秒,我们都移除 word 的前 2 个字符,并在 word 末尾添加相同的字符。
4 秒后,word 变为 “abcbabcd” 并恢复到初始状态。
可以证明,4 秒是 word 恢复到其初始状态所需的最短时间。
提示:
1 <= word.length <= 106
1 <= k <= word.length
word仅由小写英文字母组成。

Z函数

删除i个字符后,word[i…]和word公共最长前缀如果等于word[i…]的长度,则符合题意。
也就是z函数,直接用模板。

代码

核心代码

class KMPEx
{
public:	
	static vector<int> ZFunction(string s) {
		int n = (int)s.length();
		vector<int> z(n);
		z[0] = n;
		for (int i = 1, left = 0, r = 0; i < n; ++i) {
			if (i <= r)	{//如果此if,r-i+1可能为负数
				z[i] = min(z[i - left], r - i + 1);
			}
			while ((i + z[i] < n) && (s[z[i]] == s[i + z[i]])) {
				z[i]++;
			}	
			if (i + z[i] - 1 > r) left = i, r = i + z[i] - 1;
		}
		return z;//z[i] 表示S与其后缀S[i,n]的最长公共前缀(LCP)的长度
	}


};

class Solution {
		public:
			int minimumTimeToInitialState(string word, int k) {
				const int N = word.length();
				int i = k;
				auto z = KMPEx::ZFunction(word);
				for (; i < N; i += k) {
					if (z[i] >= N - i) { break; }
				}
				return i / k;
			}
		};

单元测试

	string word;
		int k;
		TEST_METHOD(TestMethod11)
		{
			word = "abacaba", k = 3;
			auto res = Solution().minimumTimeToInitialState(word, k);
			AssertEx(2, res);
		}
		TEST_METHOD(TestMethod12)
		{
			word = "abacaba", k = 4;
			auto res = Solution().minimumTimeToInitialState(word, k);
			AssertEx(1, res);
		}
		TEST_METHOD(TestMethod13)
		{
			word = "abcbabcd", k = 2;
			auto res = Solution().minimumTimeToInitialState(word, k);
			AssertEx(4, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

软件架构师何志丹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值