棘手的Google面试问题


169

我的一个朋友正在面试工作。采访中的一个问题让我思考,只想要一些反馈。

有2个非负整数:i和j。给定以下方程式,找到一种(最佳)解决方案以对i和j进行迭代,以对输出进行排序。

2^i * 5^j

因此,前几轮如下所示:

2^0 * 5^0 = 1
2^1 * 5^0 = 2
2^2 * 5^0 = 4
2^0 * 5^1 = 5
2^3 * 5^0 = 8
2^1 * 5^1 = 10
2^4 * 5^0 = 16
2^2 * 5^1 = 20
2^0 * 5^2 = 25

尝试尝试,我看不到任何模式。你的想法?


63
就程序员时间而言,最佳算法是使用两个嵌套循环生成,然后进行排序。他们为什么问这样的问题?
汤姆·齐奇

21
您可以通过查看较大的数字来确定过渡点。2^2 < 5但是2^3 > 5,此时您增加了j。我认为您可以在O(n)中生成输出,而不是O(nlgn)。@ tom-zynch两个嵌套循环为O(n ^ 2)。这个问题非常有效
Mikhail

1
只有一个输出,因此最佳解是O(n)。在下面阅读我的解决方案
米哈伊尔(Mikhail)

3
以前显然已经解决了一个类似的问题:stackoverflow.com/questions/4600048/nth-ugly-number

1
...并且OP可能应该已经选择了答案。毕竟,他已经拥有很多优秀的人才。
abeln 2011年

Answers:


123

Dijkstra在“编程纪律”中得出了雄辩的解决方案。他将问题归因于汉明。这是我对Dijkstra解决方案的实现。

int main()
{
    const int n = 20;       // Generate the first n numbers

    std::vector<int> v(n);
    v[0] = 1;

    int i2 = 0;             // Index for 2
    int i5 = 0;             // Index for 5

    int x2 = 2 * v[i2];     // Next two candidates
    int x5 = 5 * v[i5];

    for (int i = 1; i != n; ++i)
    {
        int m = std::min(x2, x5);
        std::cout << m << " ";
        v[i] = m;

        if (x2 == m)
        {
            ++i2;
            x2 = 2 * v[i2];
        }
        if (x5 == m)
        {
            ++i5;
            x5 = 5 * v[i5];
        }
    }

    std::cout << std::endl;
    return 0;
}

18
相关链接:en.wikipedia.org/wiki/Regular_number#Algorithms。顺便说一句,我认为这不是一个很好的面试问题。这是Dijkstra的(手写论文),他在其中提供并证明了解决此问题的算法:cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF
Elian Ebbing 2011年

当目标是“遍历i和j”时,您需要较少的存储容量,那么FIFO就足够了。请参阅我的Python解决方案。
GaBorgulya

7
当目标是“遍历i和j”时,这不是一个相同的问题。
mhum 2011年

这是一个非常不错的实现,使用最少的内存。即使您只想要一个数字,它也是线性存储器。
Thomas Ahle 2012年

1
@ThomasAhle不知道您是否看到了此消息,但它的末尾代码能够独立计算第n个数字。例如十亿分之一的数字
内斯(Ness)将

47

这是一种更精致的方法(比我以前的回答更精致):

想象数字放在一个矩阵中:

     0    1    2    3    4    5   -- this is i
----------------------------------------------
0|   1    2    4    8   16   32
1|   5   10   20   40   80  160
2|  25   50  100  200  400  800
3| 125  250  500 1000 2000 ...
4| 625 1250 2500 5000 ...
j on the vertical

您需要做的是从开始“遍历”此矩阵(0,0)。您还需要跟踪可能的下一步行动。当您开始时(0,0)只有两个选项:(0,1)(1,0):由于的值(0,1)较小,因此选择该选项。然后做同样为您的下一个选择(0,2)(1,0)。到目前为止,您具有以下列表:1, 2, 4。下一步是(1,0)因为该值小于(0,3)。但是,您现在有下一步选择的三个选择:(0,3),或(1,1),或(2,0)

您不需要矩阵来获取列表,但是您需要跟踪所有选择(即,当您达到125+时,将有4个选择)。


我之所以投票赞成这是因为我一直在思考,但是在一般情况下,这不是像O(i ^ 2 * j)吗?您必须为输出的每个数字检查几个数字。
汤姆·齐奇

1
@Tom确实需要检查多个数字,但这并不坏:当输出介于125和625之间的数字时,您需要查看4个值。在625和3025之间,您会看到5个值。所以实际上,它j对于每一个输出的检查
弗拉德

+1:结合以下问题:stackoverflow.com/questions/5000836/search-algorithm,看起来我们有O(n)解决方案。

@Moron darn,我不想为该算法支付25美元,但它看起来确实很有趣。
vlad

1
实际上,j ~ n^0.5对于序列中的第n个值,因为n值会填满i x j平面上的一个区域。因此,这种算法是O(n^1.5)时间和O(n^0.5)空间。但是,存在一个线性时间算法,其空间相同度为n^0.5,而下面的答案中的迷你堆算法为O(n*log(n))时间相同的n^0.5空间。
内斯

25

使用最小堆。

放入1。

提取最小 假设您得到x。

将2x和5x推入堆中。

重复。

无需存储x = 2 ^ i * 5 ^ j,您可以存储(i,j)并使用自定义比较功能。


1
堆将使lg n有时间进行操作,从而将复杂性推高到n lg n。
corsiKa 2011年

@glow:是的,不过,到目前为止我还没有看到任何O(n)解决方案:-)

@abel:那条评论很老:-)似乎他也将从(1,1)变为(4,0)也有问题。但是,将其视为杨氏矩阵(请参阅弗拉德的答案)实际上确实允许使用O(n)时间算法。

@Moron:我认为该解决方案没有任何问题。当然,在我现在刚刚检查的前30个元素中,没有什么错(这将涵盖(1,1)->(4,0)的情况)。
2011年

@abel:是的,实际上并没有尝试运行它:-)也许也有一个简单的证明了它的正确性。FWIW,它已经有我的+1。

13

基于FIFO的解决方案需要较少的存储容量。Python代码。

F = [[1, 0, 0]]             # FIFO [value, i, j]
i2 = -1; n2 = n5 = None     # indices, nexts
for i in range(1000):       # print the first 1000
    last = F[-1][:]
    print "%3d. %21d = 2^%d * 5^%d" % tuple([i] + last)
    if n2 <= last: i2 += 1; n2 = F[i2][:]; n2[0] *= 2; n2[1] += 1
    if n5 <= last: i2 -= 1; n5 = F.pop(0); n5[0] *= 5; n5[2] += 1
    F.append(min(n2, n5))

输出:

  0.                     1 = 2^0 * 5^0
  1.                     2 = 2^1 * 5^0
  2.                     4 = 2^2 * 5^0
 ...
998. 100000000000000000000 = 2^20 * 5^20
999. 102400000000000000000 = 2^27 * 5^17

6

O(n)用功能语言很容易做到这一点。该列表l2^i*5^j数字可以简单地定义为1,然后2*l5*l合并。这是Haskell的外观:

merge :: [Integer] -> [Integer] -> [Integer]
merge (a:as) (b:bs)   
  | a < b   = a : (merge as (b:bs))
  | a == b  = a : (merge as bs)
  | b > a   = b : (merge (a:as) bs)

xs :: [Integer]
xs = 1 : merge (map(2*)xs) (map(5*)xs)

merge函数在恒定时间内为您提供了一个新值。也是如此map,因此也是如此l


我认为“ k”没有定义
2011年

2
让我们直接调用此“合并”函数union,因为它将删除重复项。merge作为的一部分mergesort,必须保留来自其两个输入序列的重复项。请参阅Data.List.Ordered软件包以获取相关内容。
内斯

1
为+1 Data.List.Ordered.union。这使它成为一行:xs = 1 : union (map (2*) xs) (map (5*) xs)
Phob 2012年

@GaBorgulya是的,它包含列表的五倍,[1, 2, 4, 5,...]因此包含5*4
Thomas Ahle 2012年

1
@Phob是的,这是Data.List.Ordered.union函数。不要与混淆Data.List.union
Thomas Ahle 2013年

5

您必须跟踪它们的各个指数,以及它们的总和是多少

所以从f(0,0) --> 1 现在开始,您必须增加其中之一:

f(1,0) = 2
f(0,1) = 5

所以我们知道2是下一个-我们也知道我们可以将i的指数递增直到和为5。

您一直这样来回移动,直到达到所需的回合数。


是的。您每轮执行一次O(1)操作。有时您可以尽早进行回合,但是当您进入该回合时就不必在那里进行,因此它可以自行解决。
corsiKa 2011年

19
您如何从(1,1)转到(4,0)?请详细说明您的算法是什么。

问题是,您不仅有两种递增的可能性-例如,您并没有f(*,2)因为发现了而就完成了f(a1,b+1)>f(a2,b)。增量方法最终将在您已经输出的区域附近生成无数对。
即将

@ user515430提供的实现超出了我午休时间的能力,但这就是我想要达到的目的。
corsiKa 2011年

4

使用动态编程,您可以在O(n)中执行此操作。基本事实是,i和j的任何值都不能给我们0,而要得到1,两个值都必须为0。

TwoCount[1] = 0
FiveCount[1] = 0

// function returns two values i, and j
FindIJ(x) {
    if (TwoCount[x / 2]) {
        i = TwoCount[x / 2] + 1
        j = FiveCount[x / 2]
    }
    else if (FiveCount[x / 5]) {
        i = TwoCount[x / 2]
        j = FiveCount[x / 5] + 1
    }
}

每当您调用此函数时,请检查是否设置了i和j,如果它们不为null,则填充TwoCountFiveCount


C ++答案。不好意思的编码风格,但是我很着急:(

#include <cstdlib>
#include <iostream>
#include <vector>

int * TwoCount;
int * FiveCount;

using namespace std;

void FindIJ(int x, int &i, int &j) {
        if (x % 2 == 0 && TwoCount[x / 2] > -1) {
                cout << "There's a solution for " << (x/2) << endl;
                i = TwoCount[x / 2] + 1;
                j = FiveCount[x / 2];
        } else if (x % 5 == 0 && TwoCount[x / 5] > -1) {
                cout << "There's a solution for " << (x/5) << endl;
                i = TwoCount[x / 5];
                j = FiveCount[x / 5] + 1;
        }    
}

int main() {
        TwoCount = new int[200];
        FiveCount = new int[200];

        for (int i = 0; i < 200; ++i) {
                TwoCount[i] = -1;
                FiveCount[i] = -1;
        }

        TwoCount[1] = 0;
        FiveCount[1] = 0;

        for (int output = 2; output < 100; output++) {
                int i = -1;
                int j = -1;
                FindIJ(output, i, j);
                if (i > -1 && j > -1) {
                        cout << "2^" << i << " * " << "5^" 
                                     << j << " = " << output << endl;
                        TwoCount[output] = i;
                        FiveCount[output] = j;
                }
        }    
}

显然,您可以使用数组以外的数据结构来动态地增加存储空间等。这只是证明它可以工作的草图。


4
这看起来是一个有趣的答案,但是我看不出它是如何工作的。您可以添加更多详细信息吗?
大卫·布鲁内尔

我自己学习之后,真的看不到它是如何工作的。假设整数除法,则3的结果将与2的结果完全相同。此外,如果if条件是对非零的测试,则它将永远不会起作用,因为没有非零条目。
David Thornley,

为所有您说的人发布了C ++版本。@David您的评论是正确的,但是我的原始代码是伪代码,并且我在考虑脚本编写术语,因此请进行非整数除法,并区分空条目和值0的条目
Mikhail

该代码枚举了所有自然数,因此,根据@ThomasAhle对以下“阿拉巴马州迷失”答案的评论,它需要O(exp(sqrt(n)))产生n序列号。存在线性算法,例如由ThomasAhle给出的算法。
Will Ness 2012年

1
你是对的。以我的理解,O(n)n是最后的价值,而不是印刷品的数量,这是不正确的。我不知道如何函数式语言工作,或合并在固定时间内是如何工作的,但他的回答得到了我给予好评
米哈伊尔

2

为什么不尝试从另一个方向看呢?使用计数器来针对原始公式测试可能的答案。对不起,伪代码。

for x = 1 to n
{
  i=j=0
  y=x
  while ( y > 1 )
  {
    z=y
    if y divisible by 2 then increment i and divide y by 2
    if y divisible by 5 then increment j and divide y by 5

    if y=1 then print i,j & x  // done calculating for this x

    if z=y then exit while loop  // didn't divide anything this loop and this x is no good 
  }
}

这大约O(4^sqrt(n))在运行,因为nth序列的数量大约是该大小。
Thomas Ahle

2

这个是OEIS中的相关条目。

似乎有可能通过生成前几个项来获得有序序列,例如

1 2 4 5

然后从第二项开始,分别乘以4和5得到下两个

1 2 4 5 8 10

1 2 4 5 8 10 16 20

1 2 4 5 8 10 16 20 25

等等...

从直觉上看,这似乎是正确的,但是当然缺少证明。


2
错:( [1 2 4 5 8 10 16 20 25 32 40 50 64 80 100 125 128 160 200 250 256 320 400 500 625 ]然而500 <512 = 2 ^ 9 <625
GaBorgulya

1
@NateKerkhofs,生成了512,但由于512小于已经生成的625,所以它是乱序的;该算法将需要进一步的逻辑来按顺序排列输出-因此,该算法不像所提出的那样简单,并且根本不是同一算法。
GordonBGood

1

您知道log_2(5)= 2.32。从中我们注意到2 ^ 2 <5和2 ^ 3> 5。

现在看一下可能答案的矩阵:

j/i  0   1   2   3   4   5
 0   1   2   4   8  16  32
 1   5  10  20  40  80 160 
 2  25  50 100 200 400 800
 3 125 250 500 ...

现在,对于此示例,请按顺序选择数字。排序如下:

j/i  0   1   2   3   4   5
 0   1   2   3   5   7  10
 1   4   6   8  11  14  18
 2   9  12  15  19  23  27
 3  16  20  24...

请注意,每一行从开始该行的后面开始两列。例如,i = 0 j = 1直接在i = 2 j = 0之后。

因此,我们可以从这种模式中得出的算法是(假设j> i):

int i = 2;
int j = 5;
int k;
int m;

int space = (int)(log((float)j)/log((float)i));
for(k = 0; k < space*10; k++)
{
    for(m = 0; m < 10; m++)
    {
        int newi = k-space*m;
        if(newi < 0)
            break;
        else if(newi > 10)
            continue;
        int result = pow((float)i,newi) * pow((float)j,m);
        printf("%d^%d * %d^%d = %d\n", i, newi, j, m, result);
    }
}   

注意:此处的代码将i和j的指数值限制为小于10。您可以轻松地扩展此算法以适合任何其他任意范围。

注意:对于前n个答案,此算法的运行时间为O(n)。

注意:此算法的空间复杂度为O(1)


您写了“每一行从开始它的行后面开始两列”。然而2 ^ 9 = 512,5 ^ 4 = 625,所以这不是用于行4真
GaBorgulya

@ user678105你是对的。此代码不起作用。不好意思 由于日志的四舍五入以及我认为这无关紧要,因此该代码不起作用。
KLee1 2011年

1
解决方法如下。在充满积分系数的点的(x,y)平面上,画一条从(0,1)到(log2(5),0)的线。(0,0)在左上角。X轴向右,Y轴向下。现在从(0,0)原点绘制一条线,该线垂直于第一条线。现在,沿着第二条直线滑动第一条直线,使其离原点越来越远,并在它们交叉时收集整数坐标点。对于{2,3,5}生成的序列,它将是在(i,j,k)空间中移动的平面。如果您可以将此想法转换为代码,请大声疾呼。:)
Will Ness

1

我的实现基于以下思想:

  • 使用两个队列Q2和Q5,它们都以1初始化。我们将两个队列保持在已排序的顺序。
  • 在每一步中,从Q2或Q5中取出最小数量的元素MIN并进行打印。如果Q2和Q5都具有相同的元素-请将两者都移除。打印此号码。这基本上是两个排序数组的合并-在每一步中选择最小的元素并前进。
  • 使MIN * 2到Q2和MIN * 5到Q5。由于MIN大于先前的MIN编号,因此此更改不会破坏Q2 / Q5的不变性。

例:

Start with 1 and 1 (to handle i=0;j=0 case):
  Q2: 1
  Q5: 1
Dequeue 1, print it and enqueue 1*2 and 1*5:
  Q2: 2
  Q5: 5
Pick 2 and add 2*2 and 2*5:
  Q2: 4
  Q5: 5 10
Pick 4 and add 4*2 and 4*5:
  Q2: 8
  Q5: 5 10 20
....

Java代码:

public void printNumbers(int n) {
    Queue<Integer> q2 = new LinkedList<Integer>();
    Queue<Integer> q5 = new LinkedList<Integer>();
    q2.add(1);
    q5.add(1);
    for (int i = 0; i < n; i++) {
        int a = q2.peek();
        int b = q5.peek();
        int min = Math.min(a, b);
        System.out.println(min);
        if (min == a) {
            q2.remove();
        }
        if (min == b) {
            q5.remove();
        }
        q2.add(min * 2);
        q5.add(min * 5);
    }
}

0

计算的结果,并把它们放在一个排序列表,连同值ij


这可能会在序列的后期给您带来漏洞。例如,您将拥有,2^n*5^n但没有2^(n+1)*5^(n-1)较小的。
Thomas Ahle

@托马斯我不确定我是否遵循您的逻辑。如果您计算一个,为什么不也计算另一个?
vlad

2
@vlad你需要有一个限制你i的和j的,不是吗?否则,您将永远不会进入排序状态,因此您将永远不会返回单个值。但是对于n您选择的任何限制,您的列表都会有缺陷。
Thomas Ahle

@托马斯你的论点仍然没有道理。OP从未结束过他的结果列表。如果他这样做,则可以找到max ij
vlad

1
@vlad在阅读您的答案时,您首先要计算“结果” / 2^i*5^j值,然后对它们进行排序。如果您没有数量有限的“结果”,您将如何进入分类步骤?
Thomas Ahle

0

由Edsger Dijkstra(http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF)的user515430实现的算法可能会尽可能快。我称其2^i * 5^j为“特殊号码” 形式的每个号码。现在vlads的答案是,O(i*j)但是有一个双重算法,一个用于生成特殊数字O(i*j),另一个用于对它们进行排序(也根据链接的文章)O(i*j)

但是,让我们检查一下Dijkstra的算法(见下文)。在这种情况下n,我们要生成的特殊数字数量等于i*j。我们循环一次,1 -> n在每个循环中我们执行一个恒定的动作。所以这个算法也是O(i*j)。而且还具有非常出色的快速常数。

我在C ++中使用GMP(C ++包装器)实现,并且对的依赖boost::lexical_cast可以轻松删除(我很懒,而且谁不使用Boost?)。与编译g++ -O3 test.cpp -lgmpxx -o test。在Q6600上,Ubuntu 10.10 time ./test 1000000给出了1145ms

#include <iostream>
#include <boost/lexical_cast.hpp>
#include <gmpxx.h>

int main(int argc, char *argv[]) {
    mpz_class m, x2, x5, *array, r;
    long n, i, i2, i5;

    if (argc < 2) return 1;

    n = boost::lexical_cast<long>(argv[1]);

    array = new mpz_class[n];
    array[0] = 1;

    x2 = 2;
    x5 = 5;
    i2 = i5 = 0;

    for (i = 1; i != n; ++i) {
        m = std::min(x2, x5);

        array[i] = m;

        if (x2 == m) {
            ++i2;
            x2 = 2 * array[i2];
        }

        if (x5 == m) {
            ++i5;
            x5 = 5 * array[i5];
        }
    }

    delete [] array;
    std::cout << m << std::endl;

    return 0;
}

0

如果绘制一个矩阵,其中i为行,j为列,则可以看到该模式。从i = 0开始,然后向上移动2行并向右1列遍历矩阵,直到到达矩阵顶部(j> = 0)。然后去我+1,等等...

因此,对于我= 7,您将像这样旅行:

7, 0 -> 5, 1 -> 3, 2 -> 1, 3

对于我= 8:

8, 0 -> 6, 1 -> 4, 2 -> 2, 3 -> 0, 4

在Java中,这是i =9。它显示矩阵位置(i,j)和值。

for(int k = 0; k < 10; k++) {

    int j = 0;

    for(int i = k; i >= 0; i -= 2) {

        int value = (int)(Math.pow(2, i) * Math.pow(5, j));
        System.out.println(i + ", " + j + " -> " + value);
        j++;
    }
}

0

我的直觉

如果我将初始值设为1,其中i = 0,j = 0,那么我可以创建下一个数字为(2 ^ 1)(5 ^ 0),(2 ^ 2)(5 ^ 0),(2 ^ 0) *(5 ^ 1),...即2,4,5 ..

可以说我的数字是x。那么我可以通过以下方式创建下一个数字:

  • x * 2
  • x * 4
  • x * 5

说明

Since new numbers can only be the product with 2 or 5.
But 4 (pow(2,2)) is smaller than 5, and also we have to generate 
Numbers in sorted order.Therefore we will consider next numbers
be multiplied with 2,4,5.
Why we have taken x*4 ? Reason is to pace up i, such that it should not 
be greater than pace of j(which is 5 to power). It means I will 
multiply my number by 2, then by 4(since 4 < 5), and then by 5 
to get the next three numbers in sorted order.

测试运行

We need to take an Array-list of Integers, let say Arr.

Also put our elements in Array List<Integers> Arr.
Initially it contains Arr : [1]
  • 让我们从x = 1开始。

    接下来的三个数字是1 * 2、1 * 4、1 * 5 [2,4,5];Arr [1,2,4,5]

  • 现在x = 2

    接下来的三个数字是[4,8,10] {由于已经发生4,我们将忽略它} [8,10];Arr [1,2,4,5,8,10]

  • 现在x = 4

    接下来的三个数字[8,16,20] {8已经发生,请忽略它} [16,20] Arr [1,2,4,5,8,10,16,20]

  • x = 5

    接下来的三个数字[10,20,25] {10,20}已经存在,因此添加了[25] Arr [1,2,4,5,8,10,16,20,25]

终止条件

 Terminating condition when Arr last number becomes greater 
 than (5^m1 * 2^m2), where m1,m2 are given by user.

分析

 Time Complexity : O(K) : where k is numbers possible between i,j=0 to 
 i=m1,j=m2.
 Space Complexity : O(K)

0

只是好奇下周会发生什么,并发现了这个问题。

我认为,想法是2 ^ i的增长幅度不如5 ^ j。因此,只要下一个j步不会更大,就增加i。

C ++中的示例(Qt是可选的):

QFile f("out.txt"); //use output method of your choice here
f.open(QIODevice::WriteOnly);
QTextStream ts(&f);

int i=0;
int res=0;
for( int j=0; j<10; ++j )
{
    int powI = std::pow(2.0,i );
    int powJ = std::pow(5.0,j );
    while ( powI <= powJ  ) 
    {
        res = powI * powJ;
        if ( res<0 ) 
            break; //integer range overflow

        ts<<i<<"\t"<<j<<"\t"<<res<<"\n";
        ++i;
        powI = std::pow(2.0,i );

    }
}

输出:

i   j   2^i * 5^j
0   0   1
1   1   10
2   1   20
3   2   200
4   2   400
5   3   4000
6   3   8000
7   4   80000
8   4   160000
9   4   320000
10  5   3200000
11  5   6400000
12  6   64000000
13  6   128000000
14  7   1280000000

此解决方案缺少一些组合。例如,它不检查的情况下,其中i = 1,J = 2其中i = 1和j> 1对于该问题的任何情况下..
费德里科

@Federico:你是对的!难怪我为什么每隔6年就两次使Google面试失败,但问题几乎相同:-)
Valentin Heinitz

0

这是我的解决方案

#include <stdio.h>
#include <math.h>
#define N_VALUE 5
#define M_VALUE  5

int n_val_at_m_level[M_VALUE];

int print_lower_level_val(long double val_of_higher_level, int m_level)
{
int  n;
long double my_val;


for( n = n_val_at_m_level[m_level]; n <= N_VALUE; n++) {
    my_val =  powl(2,n) * powl(5,m_level);
    if(m_level != M_VALUE && my_val > val_of_higher_level) {
        n_val_at_m_level[m_level] = n;
        return 0;
    }
    if( m_level != 0) {
        print_lower_level_val(my_val, m_level - 1);
    }
    if(my_val < val_of_higher_level || m_level == M_VALUE) {
        printf("    %Lf n=%d m = %d\n", my_val, n, m_level);
    } else {
        n_val_at_m_level[m_level] = n;
        return 0;
    }
 }
 n_val_at_m_level[m_level] = n;
 return 0;
 }


 main()
 {
    print_lower_level_val(0, M_VALUE); /* to sort 2^n * 5^m */
 }

结果:

1.000000 n = 0 m = 0
2.000000 n = 1 m = 0
4.000000 n = 2 m = 0
5.000000 n = 0 m = 1
8.000000 n = 3 m = 0
10.000000 n = 1 m = 1
16.000000 n = 4 m = 0
20.000000 n = 2 m = 1
25.000000 n = 0 m = 2
32.000000 n = 5 m = 0
40.000000 n = 3 m = 1
50.000000 n = 1 m = 2
80.000000 n = 4 m = 1
100.000000 n = 2 m = 2
125.000000 n = 0 m = 3
160.000000 n = 5 m = 1
200.000000 n = 3 m = 2
250.000000 n = 1 m = 3
400.000000 n = 4 m = 2
500.000000 n = 2 m = 3
625.000000 n = 0 m = 4
800.000000 n = 5 m = 2
1000.000000 n = 3 m = 3
1250.000000 n = 1 m = 4
2000.000000 n = 4 m = 3
2500.000000 n = 2 m = 4
3125.000000 n = 0 m = 5
4000.000000 n = 5 m = 3
5000.000000 n = 3 m = 4
6250.000000 n = 1 m = 5
10000.000000 n = 4 m = 4
12500.000000 n = 2 m = 5
20000.000000 n = 5 m = 4
25000.000000 n = 3 m = 5
50000.000000 n = 4 m = 5
100000.000000 n = 5 m = 5

0

我知道我可能是错的,但是这里有一个非常简单的启发式方法,因为它不涉及2,3,5之类的许多数字。我们知道,对于任何i,j 2 ^ i * 5 ^ j,下一个序列将是2 ^(i-2)* 5 ^(j + 1)。作为google q,它必须有一个简单的解决方案。

def func(i, j):
 print i, j, (2**i)*(5**j)

imax=i=2
j=0
print "i", "j", "(2**i)*(5**j)"

for k in range(20):
    func(i,j)
    j=j+1; i=i-2
    if(i<0):
        i = imax = imax+1
        j=0

产生的输出为:

i j (2**i)*(5**j)
2 0 4
0 1 5
3 0 8
1 1 10
4 0 16
2 1 20
0 2 25
5 0 32
3 1 40
1 2 50
6 0 64
4 1 80
2 2 100
0 3 125
7 0 128
5 1 160
3 2 200
1 3 250
8 0 256
6 1 320

它可能最多可以使用20或200,但有时会开始跳过一些数字和/或以错误的顺序输出它们。
威尔·内斯

0

如果您按表达式中的i或j递增时实际发生的情况 2^i * 5^j,您将乘以另外2或另一个5。如果将问题重述为-给定i和j的特定值,您将如何查找下一个更大的价值,解决方案变得显而易见。

这是我们可以很直观地列举的规则:

  • 如果i > 1表达式中有一对2s(),则应将其替换为5,以获得下一个最大的数字。因此,i -= 2j += 1
  • 否则,如果有5(j > 0),我们需要将其替换为三个2。所以j -= 1i += 3
  • 否则,我们只需要再提供2个即可将值增加一个最小值。i += 1

这是Ruby中的程序:

i = j = 0                                                                       
20.times do                                                                     
  puts 2**i * 5**j

  if i > 1                                                                      
    j += 1                                                                      
    i -= 2                                                                      
  elsif j > 0                                                                   
    j -= 1                                                                      
    i += 3                                                                      
  else                                                                          
    i += 1                                                                      
  end                                                                                                                                                               
end

这不起作用,因为“ i”永远不会大于4,因此不会出现32(2 ^ 5)的倍数。
threenplusone '16

0

如果允许使用java集合,则可以在O(n ^ 2)中使用这些数字

public static void main(String[] args) throws Exception {
    int powerLimit = 7;  
     int first = 2;
     int second = 5;
    SortedSet<Integer> set = new TreeSet<Integer>();

    for (int i = 0; i < powerLimit; i++) {
        for (int j = 0; j < powerLimit; j++) {
            Integer x = (int) (Math.pow(first, i) * Math.pow(second, j));
            set.add(x);
        }
    }

    set=set.headSet((int)Math.pow(first, powerLimit));

    for (int p : set)
        System.out.println(p);
}

在这里,powerLimit必须非常仔细地初始化!取决于您想要多少个数字。


这将产生错误的结果:2 ^ 8 = 256在2 ^ 6 * 5 = 320之前丢失。枚举区域是三角形,而不是矩形。
Will Ness

@WillNess怎么样?? 当我设置powerLimit = 9时,此代码段返回以下数字1 2 4 5 8 10 16 20 25 32 40 50 64 80 100 125 128 160 200 250 256 320 400 500
kavi temre'Jul 11​​''16

不,它产生100个数字。你怎么知道在哪里停下来?您必须对此进行解释。---我在您的代码段中提到了7。为了使之成为有效答案,您必须确切说明如何为给定数量的数字设置限制,以及过量产生多少个数字。
Will Ness

0

这是我对Scala的尝试:

case class IndexValue(twosIndex: Int, fivesIndex: Int)
case class OutputValues(twos: Int, fives: Int, value: Int) {
  def test(): Boolean = {
    Math.pow(2,  twos) * Math.pow(5, fives) == value
  }
}

def run(last: IndexValue = IndexValue(0, 0), list: List[OutputValues] = List(OutputValues(0, 0, 1))): List[OutputValues] = {
  if (list.size > 20) {
    return list
  }

  val twosValue = list(last.twosIndex).value * 2
  val fivesValue = list(last.fivesIndex).value * 5

  if (twosValue == fivesValue) {
    val lastIndex = IndexValue(last.twosIndex + 1, last.fivesIndex + 1)
    val outputValues = OutputValues(value = twosValue, twos = list(last.twosIndex).twos + 1, fives = list(last.fivesIndex).fives + 1)
    run(lastIndex, list :+ outputValues)
  } else if (twosValue < fivesValue) {
    val lastIndex = IndexValue(last.twosIndex + 1, last.fivesIndex)
    val outputValues = OutputValues(value = twosValue, twos = list(last.twosIndex).twos + 1, fives = list(last.twosIndex).fives)
    run(lastIndex, list :+ outputValues)
  } else {
    val lastIndex = IndexValue(last.twosIndex, last.fivesIndex + 1)
    val outputValues = OutputValues(value = fivesValue, twos = list(last.fivesIndex).twos, fives = list(last.fivesIndex).fives + 1)
    run(lastIndex, list :+ outputValues)
  }
}

val initialIndex = IndexValue(0, 0)
run(initialIndex, List(OutputValues(0, 0, 1))) foreach println

输出:

OutputValues(0,0,1)
OutputValues(1,0,2)
OutputValues(2,0,4)
OutputValues(0,1,5)
OutputValues(3,0,8)
OutputValues(1,1,10)
OutputValues(4,0,16)
OutputValues(2,1,20)
OutputValues(0,2,25)
OutputValues(5,0,32)
OutputValues(3,1,40)
OutputValues(1,2,50)
OutputValues(6,0,64)
OutputValues(4,1,80)
OutputValues(2,2,100)
OutputValues(0,3,125)
OutputValues(7,0,128)
OutputValues(5,1,160)
OutputValues(3,2,200)
OutputValues(1,3,250)
OutputValues(8,0,256)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.