Tricky Google interview question

前端 未结 21 1569
花落未央
花落未央 2020-12-22 15:39

A friend of mine is interviewing for a job. One of the interview questions got me thinking, just wanted some feedback.

There are 2 non-negative integers: i and j. Gi

相关标签:
21条回答
  • 2020-12-22 16:13

    You have to keep track of the individual exponents of them, and what their sums would be

    so you start with f(0,0) --> 1 now you have to increment one of them:

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

    so we know 2 is the next - we also know we can increment i's exponent up until the sum surpases 5.

    You keep going back and forth like this until you're at your deisred number of rounds.

    0 讨论(0)
  • 2020-12-22 16:14

    Dijkstra derives an eloquent solution in "A Discipline of Programming". He attributes the problem to Hamming. Here is my implementation of Dijkstra’s solution.

    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;
    }
    
    0 讨论(0)
  • 2020-12-22 16:14

    If you draw a matrix with i as the row and j as the column you can see the pattern. Start with i = 0 and then just traverse the matrix by going up 2 rows and right 1 column until you reach the top of the matrix (j >= 0). Then go i + 1, etc...

    So for i = 7 you travel like this:

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

    And for i = 8:

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

    Here it is in Java going up to i = 9. It prints the matrix position (i, j) and the value.

    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 讨论(0)
  • 2020-12-22 16:16

    here is a more refined way of doing it (more refined than my previous answer, that is):

    imagine the numbers are placed in a matrix:

         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
    

    what you need to do is 'walk' this matrix, starting at (0,0). You also need to keep track of what your possible next moves are. When you start at (0,0) you only have two options: either (0,1) or (1,0): since the value of (0,1) is smaller, you choose that. then do the same for your next choice (0,2) or (1,0). So far, you have the following list: 1, 2, 4. Your next move is (1,0) since the value there is smaller than (0,3). However, you now have three choices for your next move: either (0,3), or (1,1), or (2,0).

    You don't need the matrix to get the list, but you do need to keep track of all your choices (i.e. when you get to 125+, you will have 4 choices).

    0 讨论(0)
  • 2020-12-22 16:16

    My implementation is based on the following ideas:

    • Use two queues Q2 and Q5, both initialized with 1. We will keep both queue in sorted order.
    • At every step, dequeue the smallest number element MIN from Q2 or Q5 and print it. If both Q2 and Q5 have the same element - remove both. Print this number. This is basically merging of two sorted arrays - at each step choose the smallest element and advance.
    • Enqueue MIN*2 to Q2 and MIN*5 to Q5. This change does not break the invariant of Q2/Q5 being sorted, because MIN is higher than previous MIN number.

    Example:

    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
    ....
    

    Code in 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 讨论(0)
  • 2020-12-22 16:17

    The algorithm implemented by user515430 by Edsger Dijkstra (http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF) is probably as fast as you can get. I call every number that is a form of 2^i * 5^j a "special number". Now vlads answer would be O(i*j) but with a double algorithm, one to generate the special numbers O(i*j) and one to sort them (according to the linked article also O(i*j).

    But let's check Dijkstra's algorithm (see below). In this case n is the amount of special numbers we are generating, so equal to i*j. We are looping once, 1 -> n and in every loop we perform a constant action. So this algorithm is also O(i*j). And with a pretty blazing fast constant too.

    My implementation in C++ with GMP (C++ wrapper), and dependancy on boost::lexical_cast, though that can be easily remove (I'm lazy, and who doesn't use Boost?). Compiled with g++ -O3 test.cpp -lgmpxx -o test. On Q6600 Ubuntu 10.10 time ./test 1000000 gives 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 讨论(0)
提交回复
热议问题