【问题标题】:Unlucky Numbers不吉利的数字
【发布时间】:2011-09-18 09:17:02
【问题描述】:

不吉利的数字(不是家庭作业)

有几个数字被认为是不吉利的(它只包含 4 和 7。)。我们的目标是在正整数 a 和 b 的范围内找到此类数字的计数。
例如:
输入:a = 10 b = 20
输出:0
输入:a = 30 b = 50
输出:2 (44, 47)

下面是我尝试使用静态数组方法的代码,其中我最初计算了一个 32 位整数的所有可能的不幸数字。这是在 O(n) 中完成的,稍后顺序扫描有助于获得计数,这又是一个 O(n) 操作。没有静态数组的帮助,有没有更好的方法来解决这个问题?

#define MAX_UNLUCKY 1022
static int unlucky[MAX_UNLUCKY];  
int main(int argc, char **argv) { 
    int i, j, k;  
    int a, b, factor;  
    printf("Enter the numbers : \n");  
    scanf("%d",&a);  
    scanf("%d",&b);  
    unlucky[0] = 4;  
    unlucky[1] = 7;  
    factor = 10;  
    k = 1;  
    for(i = 2; i < MAX_UNLUCKY; ++i) 
        unlucky[i] = unlucky[(i >> 1) - 1]*factor + unlucky[k ^= 1];  
    for (i = 0; i < MAX_UNLUCKY;++i) 
        if (unlucky[i] > a) break;  
    for (k = i; k < MAX_UNLUCKY;++k) { 
        if (unlucky[k] > b) break;
        printf("Unlukcy numbers = %d\n", unlucky[k]);  
    }  
    printf ("Total Number of Unlucky numbers in this range is %d\n", k-i);  
    return (0);
}  

【问题讨论】:

  • 次要优化说明:您的方法k = 1; [...] + unlucky[k ^= 1]; 生成序列4,7,4,7,4... 正在使用数组查找,您可以使用类似k = 7; [.. .] + (k = 11 - k).
  • 我很确定在log(n)^k time&space 中是可能的(常数k很小,但我懒得计算实际的k)。你只需要计算个数,不需要一一列举。您可以使用数字 10^n 下方有 2^n 个不吉利的数字。
  • @Luchian: 准确地说是 log(N) ^_^
  • 我相信建议的解决方案是 O(1)
  • @yi_H - 不,这不是作业。我在一个网站上遇到了这个问题并试图解决它。这个论坛上是否有一个协议,我必须明确指出它“不是家庭作业”,如果有,请说出来

标签: algorithm


【解决方案1】:

考虑以下几点:

中间有多少个数

0x100 and 0x111?

100,101,110,111 ( 4 = 0x111 - 0x100 + 1 )

这正是 744 和 777 (744,747,774,777) 之间有多少个不吉利的数字。

现在:

700 和 800 之间的倒霉数字数量与 744 和 777 相同。 744是大于700的最小倒霉数,777是小于800的最大倒霉数。

无需生成数字,只需减法。

对于 a = 10、b = 800 之类的情况,首先找到 10-100 和 100-800 的数字(因为您将数两次):

对于 10-100:

a = 44
b = 77

0x11 - 0x00 = 3 + 1 = 4 ( 44,47,74,77 )

对于 100-800:

a = 444
b = 777

0x111 - 0x000 = 7 + 1 = 8 ( 444, 447, 474, 477, 744, 747, 774, 777 )

所以在 10 到 800 之间:4+8 = 12 个数字,这也是正确的。

如果您有效地找到辅助数字,这也是 O(1) 时间和空间,这应该不会太难...

【讨论】:

  • 如果您按数字拆分,那么您将不会得到 O(1),因为您将进行 Θ(log(n)) 计算。也就是说,我可以想出两个简单的技巧来解决这个问题。
  • 请分享:)。此外,为简单起见,我们假设数量有限。我的意思是,如果你想全部理论上,加法是 O(n) - 因为你必须逐位添加:P
  • 你不得不承认,这不是一个坏主意... :)
  • 正好有 2^n 个 n 位数的倒霉数(和 2^(n+1)-2 最多 n 位数),因此您可以快速计算出中间范围内的值。实现这一点的一种简单方法是将 MSB 加 1(例如 0x111 -> 0x1011、0x000 -> 0x100),然后减去两个端点。但是,我确信不可能像你说的那样在小于 O(log(n)) 的时间内计算下一个/上一个不幸的数字。
  • @Luchian - 我最初确实尝试过这种方法,将它们等同于二进制方法。但是很快就到了低和高范围 - 计算中间数是一项相当繁琐的任务:) 后来上面列出的递归解决方案让我印象深刻。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多