Tricky Google interview question

前端 未结 21 1571
花落未央
花落未央 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:03

    Using dynamic programming you can do this in O(n). Ground truth is that no values of i and j can give us 0, and to get 1 both values must be 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
        }
    }
    

    Whenever you call this function check if i and j are set, if they are not null, then populate TwoCount and FiveCount


    C++ answer. Sorry for bad coding style, but i'm in a hurry :(

    #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;
                    }
            }    
    }
    

    Obviously you can use data structures other than array to dynamically increase your storage etc. This is just a sketch to prove that it works.

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

    My Intuition :

    If I take initial value as 1 where i=0, j=0, then I can create next numbers as (2^1)(5^0), (2^2)(5^0), (2^0)*(5^1), ... i.e 2,4,5 ..

    Let say at any point my number is x. then I can create next numbers in the following ways :

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

    Explanation :

    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.
    

    Test Run

    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]
    
    • Lets start with x = 1.

      Next three numbers are 1*2, 1*4, 1*5 [2,4,5]; Arr[1,2,4,5]

    • Now x = 2

      Next three numbers are [4,8,10] {Since 4 already occurred we will ignore it} [8,10]; Arr[1,2,4,5,8,10]

    • Now x =4

      Next three numbers [8,16,20] {8 already occurred ignore it} [16,20] Arr[1,2,4,5,8,10,16,20]

    • x = 5

      Next three numbers [10,20,25] {10,20} already so [25] is added Arr[1,2,4,5,8,10,16,20,25]

    Termination Condition

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

    Analysis

     Time Complexity : O(K) : where k is numbers possible between i,j=0 to 
     i=m1,j=m2.
     Space Complexity : O(K)
    
    0 讨论(0)
  • Just was curious what to expect next week and have found this question.

    I think, the idea is 2^i increases not in that big steps as 5^j. So increase i as long as next j-step wouldn't be bigger.

    The example in C++ (Qt is optional):

    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 );
    
        }
    }
    

    The output:

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

    This is very easy to do O(n) in functional languages. The list l of 2^i*5^j numbers can be simply defined as 1 and then 2*l and 5*l merged. Here is how it looks in 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)
    

    The merge function gives you a new value in constant time. So does map and hence so does l.

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

    You know that log_2(5)=2.32. From this we note that 2^2 < 5 and 2^3 > 5.

    Now look a matrix of possible answers:

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

    Now, for this example, choose the numbers in order. There ordering would be:

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

    Note that every row starts 2 columns behind the row starting it. For instance, i=0 j=1 comes directly after i=2 j=0.

    An algorithm we can derive from this pattern is therefore (assume 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);
        }
    }   
    

    NOTE: The code here caps the values of the exponents of i and j to be less than 10. You could easily extend this algorithm to fit into any other arbitrary bounds.

    NOTE: The running time for this algorithm is O(n) for the first n answers.

    NOTE: The space complexity for this algorithm is O(1)

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

    If you go by what's really happening when we increment i or j in the expression 2^i * 5^j, you are either multiplying by another 2 or another 5. If we restate the problem as - given a particular value of i and j, how would you find the next greater value, the solution becomes apparent.

    Here are the rules we can quite intuitively enumerate:

    • If there is a pair of 2s (i > 1) in the expression, we should replace them with a 5 to get the next biggest number. Thus, i -= 2 and j += 1.
    • Otherwise, if there is a 5 (j > 0), we need to replace it with three 2s. So j -= 1 and i += 3.
    • Otherwise, we need to just supply another 2 to increase the value by a minimum. i += 1.

    Here's the program in 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
    
    0 讨论(0)
提交回复
热议问题