Algorithm 不幸数字

Algorithm 不幸数字,algorithm,Algorithm,不吉利的数字(不是家庭作业) 很少有数字被认为是不吉利的(它只包含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 stati

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

很少有数字被认为是不吉利的(它只包含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);
}  
#定义MAX_不幸1022
静态整数不吉利[最大不吉利];
intmain(intargc,字符**argv){
int i,j,k;
int a,b,因子;
printf(“输入数字:\n”);
scanf(“%d”和“&a”);
scanf(“%d”和“b”);
不幸的[0]=4;
不幸的[1]=7;
系数=10;
k=1;
对于(i=2;i>1)-1]*因子+不走运[k^=1];
对于(i=0;ia)中断;
对于(k=i;kb)中断;
printf(“不吉利的数字=%d\n”,不吉利的[k]);
}  
printf(“此范围内不吉利数字的总数为%d\n”,k-i);
返回(0);
}  

考虑以下几点:

他们之间有多少个数字

0x100 and 0x111?

100,101,110,111 ( 4 = 0x111 - 0x100 + 1 )
这就是在744和777(744777)之间有多少个不吉利的数字

现在:

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)时间和空间,这应该不会太难…

次要优化注意:你的方法
k=1[…]
+不走运[k^=1]
生成序列
4,7,4,7,4…
使用数组查找,您可以使用类似
k=7的方法删除该数组查找
[…]
+(k=11-k)
。我很确定这在
log(n)^k
时空中是可能的(常数k很小,但我懒得计算实际的k)。您只需要计算计数,不需要全部枚举。你可以使用在数字10^n下面有2^n个不吉利的数字。@Luchian:log(n)确切地说^我相信建议的解决方案是在O(1)@yiu H-不,这不是家庭作业。我在一个网站上发现了这个问题,并试图解决它。在这个论坛上是否有一个协议,我必须明确地提到它是“不是一个家庭作业”,如果是这样,请说如果你把它按数字分开,那么你就不会得到O(1),因为你将进行Θ(log(n))计算。也就是说,我可以想出两个简单的技巧来解决这个问题。请分享:)。另外,为了简单起见,让我们假设有限的数字大小。我的意思是,如果你想从理论上讲,加法是O(n)-因为你必须一位数一位数地加:P你必须承认,这不是个坏主意…)正好有2^n个不吉利的数字和n个数字(以及2^(n+1)-2个不超过n个数字),因此您可以快速计算中间范围内的值。实现这一点的简单方法是将1添加到MSB(例如0x111->0x1011、0x000->0x100),然后仅减去两个端点。然而,我敢肯定,不可能像你说的那样,在不到O(log(n))的时间内计算出下一个/上一个不吉利的数字。@Luchian-我最初尝试过这种方法,将它们等同于二进制方法。但是,很快就会到达下限和上限——计算中间数是一项相当繁琐的任务:)后来,我想到了上面列出的递归解决方案。