唉,今天面试腾讯的测试开发工程师,脸被打肿了,下来查阅资料,把一道面试题讲一讲吧,题目是:
【O(N)求一个数字串能整除3的连续子串的个数,前缀和数组+对3取余组合数找规律】
例如14533254 这个字符串,如果要求只能在O(N)的时间,那么只能遍历有一重循环,而且根据以前小学学的能被3整除的数的规律,所有数字加起来能被3整除,所以利用这个来计算。
思路就是求依次将各位数字相加,得到一个数组,接着上面的14533254 这个字符串,则该数组就是{1,5,10,13,16,18,23,27},然后每位数对应莫3,就变成了{1,2,1,1,1,0,2,0}; 求出sum0(余数为0 的个数)=2, sum1(余数为1 的个数)=4, sum2(余数为2 的个数)=2,计算结果就是res=sum0+C(sum0,2)+C(sum1,2)+C(sum2,2);
其中C(sum0,2)就是一个组合数的问题,我们就以C(sum1,2)为例来说明一下
:
C(sum1,2)的意思就是冲sum1个数里面任意选择两个{1,145,1453,14533},选出两个从左到右去除相同的,身下的部分肯定能被3整除;
代码如下:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
string str;
while (cin >> str)
{
int len = str.length();
int sum = 0;
int sum0 = 0, sum1 = 0, sum2 = 0;
for (int i = 0; i < len; i++)
{
sum += str[i] - '0';
if (sum%3== 0)
sum0++;
else
if (sum % 3 == 1)
sum1++;
else
sum2++;
}
cout << "结果是:"<<sum0 + sum0 * (sum0 - 1) / 2 + sum1 * (sum1 - 1) / 2 + sum2 * (sum2 - 1) / 2 << endl;
}
return 0;
}
参考:https://www.cnblogs.com/zhazhaacmer/p/9441372.html