计数字符串中的数字101

时间:2015-03-25 06:17:29

标签: c string counting

这是一个问题:我们需要在一个由0和1组成的字符串中计算101的数量。 101是字符串的任何子序列。

  

Ex:10101有4 101。

我很确定我正确地解决了它。对于每个零,我在它之前和之后预先计算1的数量然后乘以答案然后将结果添加到res。

对于由长度为1000000的字符串组成的测试用例,代码给出了错误的答案。

我想知道我的代码中的问题在哪里?

测试用例的输入:https://he-s3.s3.amazonaws.com/media/hackathon/nitcencode03/problems/p1-6/d434839c-d-input-d4340a6.txt?Signature=IXEy0YlTGPX%2FkjsGoc%2FRxCC8bG8%3D&Expires=1427265583&AWSAccessKeyId=AKIAJLE6MUHDYS3HN6YQ

输出应该 18446708952791232852 ,但我的代码是 22531786

这是我的代码:

char s[1000005];

unsigned long long ans, res, a[1000005];

int main()
{   
    int n;

    scanf("%s", s);
    n = strlen(s);

    a[0] = 0; res = 0;
    for(int i = 1;i <= n;++i)
        a[i] = a[i - 1] + (s[i - 1] == '1');

    for(int i = 1;i <= n;++i)
        if(s[i - 1] == '0') {
            ans = a[n] - a[i];
            ans *= a[i - 1];
            res += ans;
            //if(ans < 0 || res < 0) printf("%lld %lld\n", ans, res);
        }

    printf("%llu\n", res);


    return 0;
}

1 个答案:

答案 0 :(得分:0)

在花了一些时间来解决围绕适当的存储类型,gcc代码/内存模型以及促销/溢出问题的各种问题之后,我想我已经找到了一个我满意的问题。

根据数据的大小,默认的代码/内存模型都可以。存储在a数组中的值完全在unsigned类型范围内,允许a[1000000]的静态声明工作而不会导致分段错误。 (4M存储要求)

结果值适合unsigned long(x86_64)或unsigned long long(x86)。但是,如果结果计算未转换为unsigned long,则存在一个微妙的问题,因为总和的任何组成部分都不会导致促销。

有了这个,我想我会把这个方法发布到解决方案中以防其他人好奇:

#include <stdio.h>

#define LMAX 868800

int main (int argc, char **argv) {

    if (argc < 2 ) {
        fprintf (stderr, "Error: insufficient input, usage: %s <filename>\n", argv[0]);
        return 1;
    }

    char s[LMAX] = {0};
    char *p = s;
    unsigned a[LMAX] = {0};
    unsigned long res = 0;
    unsigned n1s = 0;
    unsigned n0s = 0;
    size_t len = 0;
    size_t i = 1;
    FILE *fp = NULL;

    if (!(fp = fopen (argv[1], "r"))) {
        fprintf (stderr, "error: file open failed.\n");
        return 1;
    }

    if (!(fgets (s, LMAX - 1, fp))) {
        fprintf (stderr, "error: failed to read line from file.\n");
        return 1;
    }
    fclose (fp);

    /* fill a[i] with number of 1's before i in s   */
    while (*p && *p != '\n')
    {
        a[i] = a[i-1] + *p - '0';
        if (*p == '1') n1s += 1; else n0s +=1;
        p++; i++;
    }
    len = p - s;

    p = s;
    i = 1;
    /* for each '0' in s, multiply 1's before i with 1's after i
    and add product to result (i.e. the # of 101's for that 0) */
    while (*p && *p != '\n')
    {
        if (*p == '0')
            res += (unsigned long)a[i - 1] * (a[len] - a[i]);
        p++; i++;
    }

    printf ("\n num 1's  : %u\n num 0's  : %u\n length   : %zu\n results  : %lu\n\n",
            n1s, n0s, len, res);

    return 0;
}

<强>答案

$ ./bin/num101s d434839c-d-input-d4340a6.txt

 num 1's  : 434105
 num 0's  : 434684
 length   : 868789
 results  : 13653596984029524

此解决方案的数据文件在解决方案日期提供:Input Data

在转储到汇编程序之后,看起来以下提供了比Linux / x86_64上的原始比较更好的指令优势:

    a[i] = a[i-1] + *p - '0';

原:

    a[i] = a[i-1] + (*p == '1');