Check If Digits Are Equal in String After Operations II
Check If Digits Are Equal in String After Operations II
You are given a string s
consisting of digits. Perform the following operation repeatedly until the string has exactly two digits:
- For each pair of consecutive digits in
s
, starting from the first digit, calculate a new digit as the sum of the two digits modulo 10. - Replace
s
with the sequence of newly calculated digits, maintaining the order in which they are computed.
Return true
if the final two digits in s
are the same; otherwise, return false
.
Example 1:
Input: s = "3902"
Output: true
Explanation:
- Initially,
s = "3902"
- First operation:
(s[0] + s[1]) % 10 = (3 + 9) % 10 = 2
(s[1] + s[2]) % 10 = (9 + 0) % 10 = 9
(s[2] + s[3]) % 10 = (0 + 2) % 10 = 2
s
becomes"292"
- Second operation:
(s[0] + s[1]) % 10 = (2 + 9) % 10 = 1
(s[1] + s[2]) % 10 = (9 + 2) % 10 = 1
s
becomes"11"
- Since the digits in
"11"
are the same, the output istrue
.
Example 2:
Input: s = "34789"
Output: false
Explanation:
- Initially,
s = "34789"
. - After the first operation,
s = "7157"
. - After the second operation,
s = "862"
. - After the third operation,
s = "48"
. - Since
'4' != '8'
, the output isfalse
.
Constraints:
3 <= s.length <= 105
s
consists of only digits.
解题思路
赛时一直惯性思维把模数认为是质数求组合数,结果样例一直过不了。然后 debug 很久才意识到 10 不是质数,但发现问题后还是不会算组合数模非质数的结果。今年 lc 明显比之前难了不少,我更是直接从 2700 俯冲到了 2400,再打多几场估计就掉到 2300 了。
之前做过类似的,这类题在计算过程中不要把结果直接求和,而是用每一项表示出来。手推一下会发现每一项的系数其实就是杨辉三角的某一行,其中杨辉三角的第 行第 列的系数是 (行列标号均从 开始)。
由于最后会得到两个数,因此就需要分别计算 的结果 ,是否与 的结果 相同。
但现在需要对组合数 模 ,意味着需要求阶乘在模 意义下的乘法逆元,而 不是质数因此费马小定理不适用。又因为只有阶乘与模数 互质才存在逆元,因此很有可能是不存在逆元的!但组合数是一个整数,因此一定是有其他做法的。
当模数不是质数时,有欧拉定理 ,因此只要满足 ,那么 的逆元就是 (如果 是质数那么就变成费马小定理了)。因此对于一个数 ,当 时可以把质因子 和 提取出来,得到 的形式,那么 的结果就是 。
因此对于组合数 ,其模 的结果就是 。由于组合数是整数, 和 必然大于等于 。
所以我们需要预处理 每个数的阶乘中, 的质因子个数, 的质因子个数,以及阶乘除去质因子 和 的结果。
AC 代码如下,时间复杂度为 :
class Solution {
public:
bool hasSameDigits(string s) {
int n = s.size();
vector<int> f(n), c2(n), c5(n);
f[0] = 1;
for (int i = 1; i < n; i++) {
c2[i] = c2[i - 1];
c5[i] = c5[i - 1];
int t = i;
while (t % 2 == 0) {
c2[i]++;
t /= 2;
}
while (t % 5 == 0) {
c5[i]++;
t /= 5;
}
f[i] = f[i - 1] * t % 10;
}
vector<int> inv(10, 1);
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 3; j++) {
inv[i] = inv[i] * i % 10;
}
}
vector<int> p2(n), p5(n);
p2[0] = p5[0] = 1;
for (int i = 1; i < n; i++) {
p2[i] = p2[i - 1] * 2 % 10;
p5[i] = p5[i - 1] * 5 % 10;
}
auto get = [&](int l, int r) {
int ret = 0;
for (int i = l; i <= r; i++) {
ret = (ret + (s[i] - '0') * f[r - l] * inv[f[i - l]] * inv[f[r - i]] * p2[c2[r - l] - c2[i - l] - c2[r - i]] * p5[c5[r - l] - c5[i - l] - c5[r - i]]) % 10;
}
return ret;
};
return get(0, n - 2) == get(1, n - 1);
}
};
class Solution {
public:
bool hasSameDigits(string s) {
int n = s.size();
vector<int> p2(n), p5(n);
p2[0] = p5[0] = 1;
for (int i = 1; i < n; i++) {
p2[i] = p2[i - 1] * 2 % 10;
p5[i] = p5[i - 1] * 5 % 10;
}
int ret = s[0] - s[1], c = 1, c2 = 0, c5 = 0;
auto get = [&](int &x, int p) {
int ret = 0;
while (x % p == 0) {
ret++;
x /= p;
}
return ret;
};
for (int i = 1; i + 1 < n; i++) {
int a = n - 1 - i, b = i;
c2 += get(a, 2) - get(b, 2);
c5 += get(a, 5) - get(b, 5);
c = c * a % 10;
for (int i = 1; i < 10; i++) {
if (i * b % 10 == 1) {
c = c * i % 10;
break;
}
}
ret = (ret + c * (s[i] - s[i + 1]) * p2[c2] * p5[c5]) % 10;
}
return !ret;
}
};
参考资料
组合数模 10【力扣周赛 438】:https://www.bilibili.com/video/BV1hiAUeWEUG/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18733598
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
2023-02-24 裁剪序列
2022-02-24 三体攻击