我想用一个长整数分割一个只包含数字的长字符串。所以我试着这样做:
string divide(string s,long long num)
{
bool flag=true;
while(flag)
{
string result="";
flag=false;
long long int length=s.size();
long long int d=0,j=-1;
for(long long int i=0;i<length;i++)
{
d*=10;
d+=s[i]-48;
if(j==-1 && d/num!=0)
j=i;
result+=(char)(d/num + 48);
d%=num;
}
if(d==0)
{
s="";
for(long long int i=j;i<length;i++)
s+=result[i];
factors.push_back(num);
flag=true;
}
}
return s;
}
但我认为对于大字符串来说,它会变慢。他们用长整数划分字符串的任何更快的方法也是如此。
还请帮助我如何以更好的方式实现相同的模运算。
for(long long int i=0;i<length;i++)
{
d*=10;
d+=s[i]-48;
if(j==-1 && d/num!=0)
j=i;
result+=(char)(d/num + 48);
d%=num;
}
您在这里计算了两次d/num
,这是浪费,但我会忘记在这个循环中完全记住j
的值,只是为了速度而最大化它。您还应该将result
累积为数组而不是字符串,并且不要将long long
用于数组索引或循环计数器:
char result[1000]; // or whatever your upper limit is
for (int i = 0; i < length; i++)
{
d = d*10+s[i]-'0';
result[i] = (char)(d/num + '0');
d %= num;
}
完成后跳过前面的0。根据您的输入是如何生成的,在开始循环之前,跳过被除数中的前导零可能也是值得的。
注意,如果最后是d != 0
,您的代码将无法正常工作。如果有余数,它返回的是股息,而不是商。如果你考虑的话,这可能还可以,但这对年轻球员来说是个陷阱。
我在这里使用无符号长-长,消除了符号位不必要的混乱。
如果您的无符号长整型可以管理高达10^n的数字,那么如果您的除数大于10^(n-1),则除法将不起作用。但这对你来说可能不是问题。
假设64位无符号长整型,我们最多可以处理10^19。在读取19位数字(在任何前导零之后)之前,不需要进行任何除法运算,然后可以继续进行,为每次除法收集结果的多个数字,其中该数字取决于除数的大小。
所以,假设我们有一个除数,10^11<除数<=10^12,我们最多可以处理10^19,然后:
读取19位数字(跳过前导零),然后除法:生成结果的前8或9位数字和首字母余数
第一步类似于第3步和第4步,不同之处在于:(a)显然不需要将前导零添加到结果中,以及(b)第一次除法可以产生结果的9位,其中后续除法保证产生8位。(因为在随后的除法中,我们处理的是迄今为止的余数,它必然是<除数*10^8。)
再读取被除数的8位数字(将余数乘以10^8并将这些数字相加)。
当余数小于10^18时,读取被除数的其他数字——在结果中每增加一个数字加一个零。
除法生成答案的下8位数字并更新余数。
返回步骤2。
很明显,当数字用完时,您需要进行最后一次除法,给出结果的最后一位数字(取决于1到7位数字)。但这是SMOP。
注意:考虑到%
的速度有多慢,您可以用乘法和减法来代替它——尽管您的编译器可能会为您这样做。(遗憾的是,我在标准中找不到ulldiv()
。)
如果除数很小(对于无符号长整型),这将一次生成多个数字的结果。如果它很大,那么可能只有一两个。我不知道是否值得收集两个无符号长-长的股息并进行双字除法。。。但如果输入的数字非常长,那么一次收集18位或更多的答案对我来说很有吸引力!