【Leetcode】1071. Greatest Common Divisor of Strings(配数学证明)

题目地址:

https://leetcode.com/problems/greatest-common-divisor-of-strings/

给定两个字符串 s s s t t t,如果存在字符串 x x x使得 s = x + x + . . . + x s=x+x+...+x s=x+x+...+x并且 t = x + x + . . . + x t=x+x+...+x t=x+x+...+x,也就是说 s s s t t t都可以分割为某个相同字符串的拼接,那就返回最长满足条件的 x x x,否则返回空串。题目要求分割出 x x x的出现次数要大于等于 1 1 1,也就是说不能分出空串。我们可以将 x x x称为“最大公约串”。

首先,如果其中一个为空则直接返回空串。如果 s + t ≠ t + s s+t\ne t+s s+t=t+s也直接返回空串。然后算一下两个串长度的最大公约数 l l l,则 s s s的长 l l l的前缀即为所求。

算法正确性证明:
首先,如果 s + t ≠ t + s s+t\ne t+s s+t=t+s,那么肯定不会有最大公约串,这是显然的,所以算法正确。设 s + t = t + s s+t=t+s s+t=t+s,并且两串的长度的最大公约数等于 l l l,如果两个串长度相等,那显然成立;否则的话,不妨设 s s s短,如果 l s ∣ l t l_s|l_t lslt,容易证明成立。接着,我们只需要证明 s [ 0 : l − 1 ] s[0:l-1] s[0:l1]是最大公约串即可。为了方便起见,规定 s 0 l = s [ 0 : l − 1 ] , s 1 l = s [ l : 2 l − 1 ] , . . . s_{0l}=s[0:l-1],s_{1l}=s[l:2l-1],... s0l=s[0:l1],s1l=s[l:2l1],...,对 t t t也做类似规定。证明思路是利用字符串哈希。设 l = gcd ⁡ ( l s , l t ) l=\gcd(l_s,l_t) l=gcd(ls,lt),并且 l s = u l l_s=ul ls=ul l t = v l l_t=vl lt=vl(即有 gcd ⁡ ( u , v ) = 1 \gcd(u,v)=1 gcd(u,v)=1),令 s k l s_{kl} skl的哈希值表示为 s k s_k sk t k l t_{kl} tkl的哈希值表示为 t k t_k tk,哈希用的素数要取的足够大,以至于两个哈希值相等就等价于字符串相等。考虑整系数多项式环 Z [ X ] \mathbb{Z}[X] Z[X],那么 s + t = t + s s+t=t+s s+t=t+s等价于: s 0 + s 1 X + s 2 X 2 + . . . + s u − 1 X u − 1 + X u ( t 0 + t 1 X + . . . + t v − 1 X v − 1 ) = t 0 + t 1 X + t 2 X 2 + . . . + t v − 1 X v − 1 + X v ( s 0 + s 1 X + . . . + s u − 1 X u − 1 ) s_0+s_1X+s_2X^2+...+s_{u-1}X^{u-1}+\\X^u(t_0+t_1X+...+t_{v-1}X^{v-1})=\\t_0+t_1X+t_2X^2+...+t_{v-1}X^{v-1}+\\X^v(s_0+s_1X+...+s_{u-1}X^{u-1}) s0+s1X+s2X2+...+su1Xu1+Xu(t0+t1X+...+tv1Xv1)=t0+t1X+t2X2+...+tv1Xv1+Xv(s0+s1X+...+su1Xu1)这个式子说白了就是对应的长度 l l l的片段相等。上面的式子等价于: ( X u − 1 ) ( t 0 + t 1 X + t 2 X 2 + . . . + t v − 1 X v − 1 ) = ( X v − 1 ) ( s 0 + s 1 X + . . . + s u − 1 X u − 1 ) (X^u-1)(t_0+t_1X+t_2X^2+...+t_{v-1}X^{v-1})=\\(X^v-1)(s_0+s_1X+...+s_{u-1}X^{u-1}) (Xu1)(t0+t1X+t2X2+...+tv1Xv1)=(Xv1)(s0+s1X+...+su1Xu1)两边同时除以 X − 1 X-1 X1得: ( 1 + X + . . . + X u − 1 ) ( t 0 + t 1 X + t 2 X 2 + . . . + t v − 1 X v − 1 ) = ( 1 + X + . . . + X v − 1 ) ( s 0 + s 1 X + . . . + s u − 1 X u − 1 ) (1+X+...+X^{u-1})(t_0+t_1X+t_2X^2+...+t_{v-1}X^{v-1})\\=(1+X+...+X^{v-1})(s_0+s_1X+...+s_{u-1}X^{u-1}) (1+X+...+Xu1)(t0+t1X+t2X2+...+tv1Xv1)=(1+X+...+Xv1)(s0+s1X+...+su1Xu1)比较常数项得 s 0 = t 0 s_0=t_0 s0=t0。由于 gcd ⁡ ( u , v ) = 1 \gcd(u,v)=1 gcd(u,v)=1,所以 1 + X + . . . + X u − 1 1+X+...+X^{u-1} 1+X+...+Xu1 1 + X + . . . + X v − 1 1+X+...+X^{v-1} 1+X+...+Xv1也互素(因为复数域上它们的根分别是 u u u次单位根和 v v v次单位根除去 1 1 1,当 u u u v v v互素的时候,它们在 C [ X ] \mathbb{C}[X] C[X]上是互素的,在 Z [ X ] \mathbb{Z}[X] Z[X]上更互素)所以有 ( 1 + X + . . . + X u − 1 ) ∣ ( s 0 + s 1 X + . . . + s u − 1 X u − 1 ) (1+X+...+X^{u-1}) | (s_0+s_1X+...+s_{u-1}X^{u-1}) (1+X+...+Xu1)(s0+s1X+...+su1Xu1)而这两个多项式次数相等,所以只能相差一个常数,这个常数只能是 s 0 s_0 s0,所以得到 s 0 = s 1 = . . . = s u − 1 s_0=s_1=...=s_{u-1} s0=s1=...=su1,同理得 t 0 = t 1 = . . . = t v − 1 t_0=t_1=...=t_{v-1} t0=t1=...=tv1。又 s 0 = t 0 s_0=t_0 s0=t0,所以就有: s 0 = s 1 = . . . = s u − 1 = t 0 = t 1 = . . . = t v − 1 s_0=s_1=...=s_{u-1}=t_0=t_1=...=t_{v-1} s0=s1=...=su1=t0=t1=...=tv1也就是说 s 0 s_0 s0就是最大公约串,结论成立。

代码如下:

class Solution {
 public:
  string gcdOfStrings(string s1, string s2) {
    if (s1 + s2 != s2 + s1) return "";
    return s1.substr(0, gcd(s1.size(), s2.size()));
  }

  int gcd(int a, int b) {
    return b ? gcd(b, a % b) : a;
  }
};

时间复杂度 O ( l s + l t ) O(l_s+l_t) O(ls+lt),空间 O ( 1 ) O(1) O(1)

注解:
字符串哈希来证明字符串的结论,可以将字符串问题转化为代数问题,问题的描述和解决都会更加清楚。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值