将一个长字符串除以一个长整数



我想用一个长整数分割一个只包含数字的长字符串。所以我试着这样做:

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,然后:

  1. 读取19位数字(跳过前导零),然后除法:生成结果的前8或9位数字和首字母余数

    第一步类似于第3步和第4步,不同之处在于:(a)显然不需要将前导零添加到结果中,以及(b)第一次除法可以产生结果的9位,其中后续除法保证产生8位。(因为在随后的除法中,我们处理的是迄今为止的余数,它必然是<除数*10^8。)

  2. 再读取被除数的8位数字(将余数乘以10^8并将这些数字相加)。

  3. 当余数小于10^18时,读取被除数的其他数字——在结果中每增加一个数字加一个零。

  4. 除法生成答案的下8位数字并更新余数。

  5. 返回步骤2。

  6. 很明显,当数字用完时,您需要进行最后一次除法,给出结果的最后一位数字(取决于1到7位数字)。但这是SMOP。

注意:考虑到%的速度有多慢,您可以用乘法和减法来代替它——尽管您的编译器可能会为您这样做。(遗憾的是,我在标准中找不到ulldiv()。)

如果除数很小(对于无符号长整型),这将一次生成多个数字的结果。如果它很大,那么可能只有一两个。我不知道是否值得收集两个无符号长-长的股息并进行双字除法。。。但如果输入的数字非常长,那么一次收集18位或更多的答案对我来说很有吸引力!

最新更新