【问题标题】:How can I figure out how many characters are in a number?如何计算一个数字中有多少个字符?
【发布时间】:2019-02-16 00:05:12
【问题描述】:

所以长度:

int test1 = 1 长度为 1 个字符

int test2 = 37 长度为 2 个字符

int test3 = 82342 的长度为 5 个字符。


我可以使用以下方法找到这些 int 的字符长度:

int character_len = floor(log10(abs(whatever_vairable_here))) + 1;


我想一直数int i = 1; 直到n,但在示例代码中,我只使用了20)。有没有一种方法可以在不使用第一个 while 循环来确定我必须 malloc 的大小的情况下计算出我将使用的字符总数。我想知道我应该有多少空间malloc

int total_characters_needed = 0;
int i = 1;
while (i <= 20) {
    total_characters_needed += floor(log10(abs(i))) + 1;`
    i++;
}

char *my_numbers_as_a_string = malloc(sizeof(char) * total_characters_needed);

i = 1;
while (i <= 20) {
    sprintf(my_numbers_as_a_string, "%d", i);
    i++;
}

printf("%s\n", my_numbers_as_a_string);
// Should print out:
// 1234567891011121314151617181920
//
// If the above is unread-able its basically
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

【问题讨论】:

  • 你的问题是“从 0 到 n 的所有整数的十进制数字的位数之和是多少?”
  • 你不能为总大小设置一个上限吗?这样会分配过多的内存,但要容易得多。
  • 为什么你的问题说你以int i = 0;开头,但你的代码以i = 1开头?哪个是正确的?
  • 您需要(10 - 1) * 1 + (21 - 10) * 2 + 1 字符来适应所有数字。 (10 - 1) * 1 用于19 的范围,(21 - 10) * 2 用于1020 的范围,然后1 用于终止符。找到模式应该不难
  • 你可以使用asprintf,它不是 ISO-C,而是 GNU-C

标签: c string while-loop char int


【解决方案1】:

这更像是一个谜题。您想在字符串中存储从 1 到某个数字 x 的数字序列,因此需要所有字符的总和。 例如,设 x=77867。所以 x 是一个 5 字符长的数字。这可以使用 user10334659 给出的循环找到。

首先要注意的是,1到4位的数字基本都是填满的,不依赖于x的值。所以我们可以先计算出这些数字的字符数。

  1. 1-9:个位数。 #数字 = 9 。 => 字符 = 9 x 1
  2. 10-99:2 个字符。 #numbers = 90. => 字符 = 90 x 2
  3. 100-999:3 个字符。 # 数字 = 900. => 字符 = 900 x 3
  4. 1000-9999:4 个字符。 # 数字 = 9000。=> 字符 = 9000 x 4

因此,从 1 到最大 y 位数的所有数字的总字符数为:

9 ( 10^0 x 1 + 10^1 x 2 + ... + 10^(y-1) x y )

现在我们只需要计算从10^(y)x(即 (y+1)- 位数)的总数。对于我们的例子,10000 - 77867:#numbers = 67688 => characters = 67688x5。

时间复杂度

设最大数为n。那么 y+1 可以在 O(log(n)) 时间内计算出来。查找从 1 到 y 数字的字符也需要 O(log(n)) 时间。最后,在 O(1) 时间内找到了从 10^y 到 n 的字符数。

所以这个算法可以在 O(log(n)) 时间内找到字符总数,而不是简单的 O(n) 时间循环。

【讨论】:

  • 对不起,我偷了你的雷,把算法写出来了。你的答案+我的答案=完美的答案。投赞成票!
  • 不错的时机 :) 我觉得我花了太多时间来格式化答案。代码会快得多:D
【解决方案2】:

以下代码计算从 1 到 n 的所有整数的十进制数字的总位数:

int Digits = 0;
int LeadingZeros = 0;
for (int t = n; 0 < t; t /= 10)
{
    ++Digits;
    LeadingZeros = 10*LeadingZeros + 1;
}

int TotalDigits = Digits * (n+1) - LeadingZeros;

推理:循环计算n 中的位数,将此数字放入Digits。如果我们将 0 到 n 的所有整数写成带有 Digits 数字的十进制数字(使用前导零,例如“003”),那将使用 Digits * (n+1) 数字。从中,我们要减去前导零的数量。 (对于零,我们想减去它的所有零,所以它对我们的计数没有净影响。)

对于n,从 1 到 9,只有一个“0”要减去,一个对应 0。对于 n,从 10 到 99,我们想将“01”中的 9 个前导零减去“ 09”,以及“00”中的两个零。因此,对于 10 到 99,我们在 1 到 9 中减去与 n 相同的一个前导零,但还要减去十个前导零。同样,对于从 100 到 999 的 n,我们减去前导零再加上 100——从 0 到 99 的每个数字再加一个。最终,LeadingZeros 的数量是数字 111…111,其位数与 @ 相同987654332@。我们可以看到循环在LeadingZeros 中计算这个,所以使用的总位数是Digits * (n+1) - LeadingZeros

在为这些数字准备缓冲区时,应再包含一个字符作为终止空值。此外,sprintf(my_numbers_as_a_string, "%d", i); 会将新号码写入my_numbers_as_a_string 的开头。要连接新数字,应规定写入之前数字的末尾。

【讨论】:

  • 是的,上调了。出于兴趣,您为什么选择/=10 而不是乘法?
  • @Bathsheba:主要是因为/10首先出现在我的脑海中,而且*10有溢出的风险。另一方面,Digits * (n+1) 也可以在- LeadingDigits 减少它之前溢出。因此,无论哪种情况,理想的解决方案都需要更多的修补。尽管*10 只会在总位数溢出后很久才会溢出。但至少/10 在溢出后面的计算之前停止,而*10 可以永远循环。
  • 1) 很好奇,为什么 0 &lt; tt &gt; 0?后者,IMO,更清楚。 2)Digits * (n+1) - LeadingZeros 可以简单地使用更广泛的数学 - 也许n+1ull,如果可用,以防止溢出。 3)良好而有效的代码答案。 O(ln(n))。
  • @chux:在没有充分理由的情况下,我采用了始终使用&lt;&lt;= 的做法。这没什么大不了的。它只是一个一致的模式,可以帮助我保持复杂的复合条件和循环解开。我也更喜欢半开区间,例如 [0, n),这也意味着 i &lt; n 优于 i &lt;= n-1。半开区间有一些很好的性质,例如 [0, 2n) 是 [0, n) 的两倍,而 [0, 2n] 不是 [0, n] 的两倍。
  • @EricPostpischil:是的,确实非常精致。在 C++ 中,“
【解决方案3】:

如果你写出从 1 到 n 的数字,要计算所写的位数,请使用类似

unsigned long digits(unsigned long n) 
{ 
    unsigned long total = 0;  
    for (unsigned long i = 1; i <= n; i *= 10){
        total += (1 + n - i); 
    }
    return total;  
} 

例如,n11 生成 1234567891011,它有 13 个数字。

该算法存在一个缺陷,即它可以在足够大的n 上循环,并且截止值取决于您平台上unsigned long 的范围。将 n 限制为不大于 ULONG_MAX / 10 - 1 就足够了。

【讨论】:

  • 更好,但仍然使用digits(MAX) 无限循环。
  • @chux。关于你的第二点,哎呀。在你的第一个,需要一点思考。当我在回家的路上遇到问题时,我会考虑一下,除非你有什么东西在你的袖子里,在这种情况下,我会在 wiki 上找到答案。
  • 1) 为防止无限循环,不能使用i_same_type_n &lt;= n。 2) 由于digits(x) 的范围比域x 更宽,所以我们有OF 的可能性留在一种类型。当某些类型存在比int/unsigned 宽得多时,代码可以使用更宽的类型。例如digits(unsigned n) ... uintmax_t total, i。由于 OP 谈到了分配,size_t 是最广泛的类型需要。即使有些角落被破解,这段代码的简单性也是甜蜜的。
  • @chux:确实提出了很好的观点。我正在考虑n 的最高可能值的封闭形式近似。
【解决方案4】:

只是将数字打印成字符串,然后计算字符串长度?还是太简单了?

int numdigits(int n)
{
    char buf[64];
    return(sprintf(buf,"%d",n));
}

【讨论】:

    猜你喜欢
    • 2013-11-01
    • 1970-01-01
    • 2019-11-03
    • 1970-01-01
    • 2021-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多