KMP中的getnext函数中的周期原理,和重要性质

-----------------------

-----------------------

 k    m        x      j       i

由上,next【i】=j,两段红色的字符串相等(两个字符串完全相等),s[k....j]==s[m....i]

设s[x...j]=s[j....i](xj=ji)

则可得,以下简写字符串表达方式

kj=kx+xj;

mi=mj+ji;

因为xj=ji,所以kx=mj,如下图所示

 

-------------

      -------------

 k   m        x     j   

看到了没,此时又重复上面的模型了,kx=mj,所以可以一直这样递推下去

所以可以推出一个重要的性质len-next[i]为此字符串的最小循环节(i为字符串的结尾),另外如果len%(len-next[i])==0,此字符串的最小周期就为len/(len-next[i]);

 

### 错误分析 在给定的 `getnext` 函数实现中存在一些逻辑问题,这些问题可能导致程序行为不符合预期。 #### 1. 初始化问题 函数中的 `next[0] = -1;` 是合理的,因为这是 KMP 算法的一部分。然而,在后续处理过程中,当 `j == -1` 时,仍然会执行 `s[j+1] != s[i]` 的比较操作[^3]。这种情况下可能会导致未定义的行为,因为在某些编程环境中访问数组越界是不允许的操作。 #### 2. 更新条件不充分 另一个问题是更新 `j++` 赋值 `next[i]=j` 的顺序以及判断条件不够严谨。具体来说: - 当前代码仅在 `if(s[j+1] == s[i])` 成立的情况下才增加 `j` 并设置 `next[i]`。 - 如果两个字符相等,则应该先让 `j++` 再将其作为新位置保存到 `next[i]` 中。 - 同样重要的是即使两者不同也应当考虑将当前索引设为 `-1` 或者其他适当初始值来表示没有匹配发生。 因此建议修改这部分逻辑如下所示: ```cpp while (j >= 0 && s[j + 1] != s[i]) { j = next[j]; } // 不论是否匹配都需要前进一位 j++; next[i] = j; ``` #### 3. 边界情况处理不当 最后一点是在计算周期性的判定表达式里有一个加号的位置错误: ```cpp len % (len - next[len - 1] + 1) == 0 ``` 这里实际上应该是减去而不是加上一,这样才能得到正确的子串长度用于检测是否存在重复模式。修正后的版本应改为: ```cpp len % (len - next[len - 1] - 1) == 0 ``` 通过以上调整可以提高此部分代码的健壮性准确性。 ### 修改后的代码示例 以下是经过改进后的 C++ 实现方式: ```cpp vector<int> getnext(string s) { vector<int> next(s.size()); int j = -1; next[0] = -1; for (int i = 1; i < s.size(); ++i) { while (j >= 0 && s[j + 1] != s[i]) { j = next[j]; } j++; // 移动至下一状态 next[i] = j; // 额外优化:避免不必要的回溯 if (s[i] == s[next[i]]) next[i] = next[next[i]]; } return next; } bool repeatedSubstringPattern(const string& s) { if (s.empty()) return false; auto next = getnext(s); const size_t len = s.length(); // 正确地检查是否有重复模式 return next.back() != -1 && len % (len - next.back() - 1) == 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值