我想划分一个只包含长整数的长字符串。所以我尝试这样做:
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;
}
但是我觉得大字符串的速度很慢。所以用任何更快的方法来划分长整数字符串。
另外,请帮助我以更好的方式实现模数操作。
答案 0 :(得分: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;
}
你在这里计算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;
}
然后在完成后跳过前导零。根据输入的生成方式,在开始循环之前跳过被除数中的前导零值也是值得的。
注意,如果d != 0
结尾,您的代码无法正常运行。如果有余数,则返回被除数而不是商。如果你正在分解这可能是好的,但对于年轻球员来说这是一个陷阱。
答案 1 :(得分:0)
我在这里使用unsigned long long,消除了符号位的不必要的混乱。
如果你的无符号长多头可以管理最多10 ^ n的数字,那么如果你的除数是&gt;则该除法将不起作用。 10 ^(N-1)。但这对你来说可能不是问题。
假设64位无符号长long,我们最多可以处理10 ^ 19。在您读取19位数(在任何前导零之后)之后,不需要进行任何分割,然后您可以继续,为每个分区收集结果的多个数字 - 其中该数字取决于除数的大小
所以,假设我们有一个除数,10 ^ 11&lt; divisor&lt; = 10 ^ 12,我们最多可以处理10 ^ 19,然后:
读取19位数(跳过前导零),然后除以:这将是 生成结果的前8位或9位数和初始值 其余部分。
第一步类似于步骤3和4,除了:(a)显然不需要在结果中添加前导零,并且(b)第一个分区可能产生9位数的结果,其中保证分裂产生8.(因为在随后的分裂中,我们正在处理迄今为止的余数,这必然是&lt; divisor * 10 ^ 8.)
读取被除数的另外8位数(将余数乘以10 ^ 8并加上这些数字)。
当剩余部分小于10 ^ 18时,读取被除数的更多数字 - 为结果的每个更多数字添加零。
除以生成答案的后8位数字并更新余数。
返回第2步。
显然,当你用完数字时,你需要进行最后的除法,给出结果的最后数字(取决于1到7位数)。但这是一个SMOP。
注意:考虑到%
的速度有多慢,您可以通过乘法和减法来替换它 - 尽管您的编译器可能会为您执行此操作。 (可悲的是,我在标准中找不到ulldiv()
。)
如果你的除数很小(对于无符号的长整数),这将一次生成许多数字的结果。如果它很大,那么也许只有一两个。我不知道是否值得收集两个未签名的长期股息并进行双字除法......但如果输入数字非常非常长,那么一次收集18位或更多位数的答案看起来诱惑我!