Хитрі питання щодо інтерв'ю 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). Це питання є дуже актуальним
— Михайло

1
Є лише один вихід, тому оптимальним рішенням є O (n). Прочитайте моє рішення нижче
— Михайло

3
Подібне питання було вирішено і раніше: stackoverflow.com/questions/4600048/nth-ugly-number .

1
... і ОП, ймовірно, вже повинен вибрати відповідь. Зрештою, у нього вже багато хороших.
— abeln

Відповіді:


123

Дійкстра отримує красномовне рішення у "Дисципліні програмування". Він приписує проблему Хеммінгу. Ось моя реалізація рішення Дейкстри.

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
— Еліан

Коли мета - "повторити і i j", вам потрібна менша ємність для зберігання, FIFO достатньо. Дивіться моє рішення Python.
— ГаБоргуля

7
Коли мета - "повторити над i та j", це не та сама проблема.
— mhum

Це дійсно приємна реалізація, використовуючи мінімум пам'яті. Це лінійна пам'ять, навіть якщо вам потрібно лише одне число.
— Томас Ейл

1
@ThomasAhle Не знаю, чи ви це бачили, але в кінці є код, який може обчислити n-е число в ізоляції. Наприклад, мільярдне число .
— Буде Несс

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
@Тому вам доведеться перевірити більше одного числа, але це не так вже й погано: коли ви виводите цифри між 125 і 625, вам потрібно переглянути 4 значення. між 625 і 3025, ви дивитесь на 5 значень. так справді, це jперевірки на кожен 1 вихід
— vlad

+1: Поєднайте це питання: stackoverflow.com/questions/5000836/search-algorithm і виглядає так, що у нас є рішення O (n).

@Moron darn, я не хочу платити $ 25 за цей алгоритм, але це виглядає цікаво.
— влада

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.

витяг-Мін. Скажіть, ви отримуєте х.

Натисніть 2x і 5x у купу.

Повторіть.

Замість того, щоб зберігати x = 2 ^ i * 5 ^ j, ви можете зберігати (i, j) і використовувати спеціальну функцію порівняння.


1
Купа дасть lg n час на свої операції, що підштовхує складність до n lg n.
— corsiKa

@glow: Так, поки що я не бачу жодних O (n) рішень, однак :-)

@abel: Цей коментар старий :-) Схоже, у нього також будуть проблеми з (1,1) до (4,0). Але розглядати його як матрицю Юнга (див. Відповідь Влада) насправді дозволяє алгоритм часу O (n).

@Moron: Я не думаю, що в цьому рішенні нічого поганого. Безумовно, нічого поганого в перших 30 елементах, які я зараз перевірив (що охоплює випадок (1,1) -> (4,0)).
— abeln

@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)на функціональних мовах. Список lз 2^i*5^jномерів може бути просто визначений як 1і те 2*lі 5*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" не визначено
— Ither

2
давайте просто назвемо цю функцію "злиття" unionзамість цього, оскільки вона видаляє дублікати. merge, як частина mergesort, має зберігати дублікати, що надходять з обох вхідних послідовностей. Дивіться Data.List.Orderedпакет для пов'язаних матеріалів.
— Буде Несс

1
+1 для Data.List.Ordered.union. Це робить його одним рядком:xs = 1 : union (map (2*) xs) (map (5*) xs)
— Phob

@GaBorgulya Так, цей список містить п'ять разів, [1, 2, 4, 5,...]так що він включає 5*4.
— Томас Ейл

1
@Phob Так, це Data.List.Ordered.unionфункція. Не плутати з Data.List.union.
— Thomas Ahle

5

Ви повинні слідкувати за окремими їх показниками та якими будуть їх суми

так що для початку f(0,0) --> 1 ви повинні збільшити один з них:

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

тому ми знаємо, що 2 - наступне - ми також знаємо, що можемо збільшити показник i до тих пір, поки сума не перевищить 5.

Ви продовжуєте так і назад, поки не досягнете потрібної кількості раундів.


Так. Ви робите одну операцію O (1) для кожного раунду. Іноді ти робиш раунд рано, але коли ти дістаєшся до цього раунду, не потрібно робити це там, тому він виходить сам.
— corsiKa

19
Як ви переходите від (1,1) до (4,0)? Будь ласка, детально розкажіть, який саме ваш алгоритм.

Проблема полягає в тому, що у вас не просто дві додаткові можливості - наприклад, ви не f(*,2)робите лише тому, що ви це знайшли f(a1,b+1)>f(a2,b). Поступовий підхід врешті-решт створить необмежену кількість пар сусіднього регіону, який ви вже отримали.
— Буря,

@ user515430 надав реалізацію, яка була більше, ніж я міг зробити на обідній перерві, але це те, що я намагався отримати.
— corsiKa

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 i j, якщо вони не є нульовими, тоді заповніть TwoCountіFiveCount


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. Більше того, якщо умови, якщо умови є тестами для ненульових, це ніколи не буде працювати, оскільки немає ненульових записів.
— Девід Торнлі

Опублікував версію на C ++ для всіх, хто говорить вас. @David Ваші коментарі правильні, але моїм оригінальним кодом був псевдо-код, і я думав у сценарії термінів, тому не ціле поділ і розмежування між нульовим записом та введенням значення 0
— Михайло

цей код перераховує всі натуральні числа, тому за коментарем @ThomasAhle на відповідь "Загублений в Алабамі" нижче, це потрібно O(exp(sqrt(n))), щоб створити nномери послідовності. Лінійний алгоритм існує, наприклад, заданий ThomasAhle.
— Буде Несс

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кількість послідовностей приблизно такого розміру.
— Томас Ейл

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.

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

Зауважте, що кожен рядок починається з 2 стовпців за рядком, починаючи його. Наприклад, 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. Ви можете легко розширити цей алгоритм, щоб вписатись у будь-які інші довільні межі.

ПРИМІТКА. Час виконання цього алгоритму становить O (n) для перших n відповідей.

ПРИМІТКА: Складність простору для цього алгоритму становить O (1)


Ви написали "кожен рядок починається з 2 стовпців за рядком, починаючи його". Однак 2 ^ 9 = 512 і 5 ^ 4 = 625, тому це не вірно для рядка 4.
— ГаБоргуля

@ user678105 Ви праві. Цей код не працює. Вибачте всіх. Цей код не працює через округлення журналу та моєму припущенні, що це не мало значення.
— KLee1

1
Ось як це виправити. На площині (x, y), повної точок з інтегральними коефіцієнтами, проведемо лінію від (0,1) до (log2 (5), 0). (0,0) знаходиться у верхньому лівому куті. Вісь X йде вправо, вісь Y йде вниз. Тепер проведемо лінію з точки початку (0,0), яка перпендикулярна 1-й лінії. Тепер просуньте перший рядок по другому, далі та далі від початку, і збирайте цілочисельні координати, коли вони перетинаються. Для {2,3,5} -породженої послідовності це буде площина, що рухається поперек, у (i, j, k) просторі. Якщо ви можете перекласти цю ідею в код, дайте мені кричати. :)
— Буде Несс

1

Моя реалізація базується на таких ідеях:

  • Використовуйте дві черги Q2 та Q5, обидві ініціалізовані з 1. Ми збережемо обидві черги у відсортованому порядку.
  • На кожному кроці видаліть з Q2 або Q5 найменший числовий елемент MIN та надрукуйте його. Якщо і Q2, і Q5 мають один і той же елемент - видаліть обидва. Роздрукуйте цей номер. Це в основному злиття двох відсортованих масивів - на кожному кроці вибирайте найменший елемент і просувайтесь.
  • Запишіть MIN * 2 до Q2 та MIN * 5 до Q5. Ця зміна не порушує сортування інваріанта Q2 / Q5, оскільки MIN вище, ніж попереднє число MIN.

Приклад:

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

обчислити результати та помістити їх у відсортований список разом із значеннями для iтаj


Це, ймовірно, дасть вам дірки в подальшому кінці вашої послідовності. Наприклад, ви будете мати, 2^n*5^nале не той, 2^(n+1)*5^(n-1)який менший.
— Томас Ейле

@Thomas Я не впевнений, що я дотримуюся вашої логіки. Якщо ви обчислюєте одне, чому б ви також не обчислили інше?
— влада

2
@vlad Потрібно мати обмеження на ваші iі та j, чи не так? Інакше ви ніколи не дістанетесь до стану сортування, а значить, ніколи не повернете жодного значення. Але за будь-якого обраного nвами обмеження ваш список буде недосконалим.
— Thomas Ahle

@Томас ваш аргумент досі не має сенсу. ОП ніколи не визначав припинення свого списку результатів. Якщо він це зробить, ви можете знайти максi і j.
— vlad

1
@vlad Коли я читаю вашу відповідь, ви спочатку обчислюєте "результати" / 2^i*5^jзначення, а потім сортуєте їх. Якщо у вас немає обмеженої кількості "результатів", як ви коли-небудь перейдете до етапу сортування?
— Thomas Ahle

0

Алгоритм, реалізований користувачем515430 Edsger Dijkstra (http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF), ймовірно, такий швидкий, наскільки ви можете отримати. Я називаю кожне число, яке є формою 2^i * 5^j"спеціального номера". Тепер відповісти власників було б, O(i*j)але з подвійним алгоритмом, один для створення спеціальних чисел O(i*j)і один для їх сортування (відповідно до пов'язаної статтіO(i*j) .

Але давайте перевіримо алгоритм Дейкстри (див. Нижче). У цьому випадку 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.10time ./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). Потім перейдіть i + 1 і т.д. ...

Тож для i = 7 ви подорожуєте так:

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

А для i = 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. то я можу створити наступні числа такими способами:

  • х * 2
  • х * 4
  • х * 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]; Зар. [1,2,4,5]

  • Тепер х = 2

    Наступні три числа - [4,8,10] {Оскільки 4 вже відбулися, ми проігноруємо його} [8,10]; Зар [1,2,4,5,8,10]

  • Тепер х = 4

    Наступні три числа [8,16,20] {8 вже відбулося ігноруйте його} [16,20] Arr [1,2,4,5,8,10,16,20]

  • х = 5

    Наступні три числа [10,20,25] {10,20} вже так [25] додано Арр [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 ^ я зростає не такими великими кроками, як 5 ^ j. Тому збільшуйте i до тих пір, поки наступний j-крок не буде більшим.

Приклад в 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: Ви праві! Не дивно, чому я два рази провалював google-інтерв'ю з інтервалом у 6 років, але майже з тими ж питаннями :-)
— Валентин Хайніц

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 -= 2і j += 1.
  • В іншому випадку, якщо є 5 ( j > 0), нам потрібно замінити його на три 2. Так j -= 1і i += 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

Це не працює, оскільки "я" ніколи не стає більшим, ніж 4, тому жодне кратне число 32 (2 ^ 5) ніколи не з’явиться.
— threenplusone

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. область перерахування трикутна, а не прямокутна.
— Буде Несс

@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

ні, він видає 100 чисел. як ти знаєш, де зупинитися? ви повинні пояснити це. --- У вашому фрагменті коду я вказав 7. щоб це було правильною відповіддю, ви повинні точно пояснити, як встановити ліміт для заданої кількості чисел і скільки номерів буде перевищувати .
— Буде Несс

0

Ось моя спроба зі Скалою:

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)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.