Zor Google röportaj sorusu


169

Bir arkadaşım bir iş için röportaj yapıyor. Röportaj sorularından biri beni düşündürdü, sadece geri bildirim almak istedi.

Negatif olmayan 2 tamsayı vardır: i ve j. Aşağıdaki denklem göz önüne alındığında, i ve j üzerinde, çıktı sıralanacak şekilde yinelenen (optimal) bir çözüm bulun.

2^i * 5^j

İlk birkaç tur şöyle görünecektir:

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

Elimden geleni dene, bir desen göremiyorum. Senin düşüncelerin?


63
Programcı zamanı açısından en uygun algoritma, iki iç içe döngü ile üretip sıralamaktır. Neden böyle sorular soruyorlar?
Tom Zych

21
Hangi sayının daha büyük olduğuna bakarak geçiş noktalarını belirleyebilirsiniz. 2^2 < 5ama 2^3 > 5bu noktada j'yi artırırsınız. Bence çıktıyı O (nlgn) yerine O (n) olarak üretebilirsiniz. @ tom-zynch iki iç içe ilmek O (n ^ 2) 'dir. Bu soru çok geçerli
Mikhail

1
Sadece bir çıkış var, bu yüzden optimal çözüm O (n). Aşağıdaki çözümümü okuyun
Mikhail

3
Görünüşe göre benzer bir soru daha önce ele alındı: stackoverflow.com/questions/4600048/nth-ugly-number .

1
... ve muhtemelen OP zaten bir cevap seçmeli. Sonuçta, zaten çok iyi olanları var.
abeln

Yanıtlar:


123

Dijkstra "Bir Programlama Disiplini" nde etkili bir çözüm üretmektedir. Sorunu Hamming'e bağlıyor. İşte Dijkstra'nın çözümünü uygulamam.

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
İlgili bağlantı: en.wikipedia.org/wiki/Regular_number#Algorithms . Bu arada çok güzel bir röportaj sorusu olduğunu sanmıyorum. İşte Dijkstra'nın bu sorun için bir algoritma sağladığı ve kanıtladığı bir (el yazısı kağıdı): cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF
Elian Ebbing

Hedef "i ve j üzerinden yineleme yapmak" olduğunda daha az depolama kapasitesine ihtiyacınız vardır, bir FIFO yeterlidir. Python çözümüme bakın.
GaBorgulya

7
Hedef "i ve j üzerinde yineleme yapmak" olduğunda, aynı sorun değildir.
mhum

Bu, en az bellek kullanan gerçekten güzel bir uygulamadır. Gerçi sadece bir sayı isteseniz bile doğrusal bellektir.
Thomas Ahle

1
Eğer gördüyse @ThomasAhle Do not know bu ama tek başına n'inci sayı hesaplama yeteneğine sahiptir ucunda kodu vardır. Mesela milyarda bir sayı gibi .
Ness Ness

47

İşte bunu yapmanın daha rafine bir yolu (önceki cevabımdan daha rafine, yani):

sayıların bir matrise yerleştirildiğini hayal edin:

     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

tek yapmanız gereken bu matrisi 'başlamak' (0,0). Ayrıca, olası sonraki hamlelerinizin ne olduğunu da takip etmeniz gerekir. En başladığınızda (0,0)size sadece iki seçenek vardır: Ya (0,1)ya (1,0): değeri beri (0,1)küçüktür, bunu seçin. sonra bir sonraki seçiminiz için aynısını yapın (0,2)veya (1,0). Şimdiye kadar, aşağıdaki liste var: 1, 2, 4. Bir sonraki hamleniz, (1,0)oradaki değer küçük olduğundan (0,3). Ancak, şimdi bir sonraki hamleniz için üç seçeneğiniz var : ya (0,3), ya da (1,1), ya da (2,0).

Listeyi almak için matrise ihtiyacınız yoktur, ancak tüm seçimlerinizi takip etmeniz gerekir (yani 125+'ye ulaştığınızda 4 seçeneğiniz olacaktır).


Aynı çizgide düşündüğüm için buna oy verdim, ancak genel olarak, bu O (i ^ 2 * j) gibi bir şey olmaz mı? Çıkardığınız her sayı için birkaç sayıyı kontrol etmeniz gerekir.
Tom Zych

1
@Tom birden fazla sayıyı kontrol etmeniz gerekiyor, ancak o kadar da kötü değil: 125 ve 625 arasındaki sayıları çıkardığınızda, 4 değere bakmanız gerekir. 625 ve 3025 arasında 5 değere bakarsınız. gerçekten, jher 1 çıkış için kontroller
vlad

+1: Bu soru ile birleştirin: stackoverflow.com/questions/5000836/search-algorithm ve bir O (n) çözümümüz var gibi görünüyor.

@Moron lanet olsun, bu algoritma için 25 dolar ödemek istemiyorum, ama ilginç görünüyor.
vlad

1
aslında, değerler bir düzlemdeki j ~ n^0.5n-inci değer için, çünkü ndeğerler i x jdüzlemdeki bir alanı doldurur . Yani bu algo O(n^1.5)zaman ve O(n^0.5)mekan. Fakat aynı boşluk kompleksi ile doğrusal bir zaman algo vardır n^0.5ve aşağıdaki cevabın mini yığın algo O(n*log(n))aynı n^0.5boşluk ile zaman .
Ness Ness

25

Min-yığın kullanın.

Koy 1.

çıkarmak-Min. Diyelim ki x aldınız.

Yığının içine 2x ve 5x itin.

Tekrar et.

X = 2 ^ i * 5 ^ j depolamak yerine (i, j) kaydedebilir ve özel bir karşılaştırma işlevi kullanabilirsiniz.


1
Bir yığın, işlemlerinde lg n süresine neden olur ve bu da karmaşıklığı n lg n'ye iter.
corsiKa

@glow: Evet, şimdiye kadar yayınlanan herhangi bir O (n) çözümü göremiyorum :-)

@abel: Bu yorum eski :-) Görünüşe göre (1,1) 'den (4,0)' a kadar problemleri olacak. Ancak bunu bir gençin matrisi olarak görmek (vlad cevabına bakınız) aslında bir O (n) zaman algoritmasına izin verir.

@Moron: Bu çözümde yanlış bir şey olduğunu sanmıyorum. Kesinlikle şu anda kontrol ettiğim ilk 30 elementte yanlış bir şey yok (bu (1,1) -> (4,0) davayı kapsayacak).
Abeln

@abel: Evet aslında çalıştırmayı denemedim :-) Belki de doğruluğunun kolay bir kanıtı var. FWIW, zaten + 1'ime sahip.

13

FIFO tabanlı bir çözüm daha az depolama kapasitesine ihtiyaç duyar. Python kodu.

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

çıktı:

  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)İşlevsel dillerde bunu yapmak çok kolaydır . Liste lait 2^i*5^jnumaralar basitçe olarak tanımlanabilir 1ve sonra 2*lve 5*lbirleşti. Haskell'de şöyle görünüyor:

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)

mergeFonksiyon size sabit zamanda yeni bir değer verir. Yani yapar mapve dolayısıyla yapar l.


Bence 'k' tanımlı değil
Ither

2
unionkopyaları kaldırdığı için bu "birleştirme" işlevini kullanalım. merge, bir parçası olarak mergesort, her iki giriş dizisinden de gelen kopyaları korumalıdır. Data.List.Orderedİlgili şeyler için pakete bakın .
Ness Ness

1
İçin +1 Data.List.Ordered.union. Bu bir satır yapar:xs = 1 : union (map (2*) xs) (map (5*) xs)
Phob

@GaBorgulya Evet, listenin beş katı içerir, bu [1, 2, 4, 5,...]yüzden içerir 5*4.
Thomas Ahle

1
@Phob Evet, bu Data.List.Ordered.unionişlev. Kafanız karışmasın Data.List.union.
Thomas Ahle

5

Onların bireysel üslerini ve toplamlarının ne olacağını takip etmelisiniz

böylece f(0,0) --> 1 şimdi bunlardan birini artırmalısınız:

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

bu yüzden 2'nin bir sonraki olduğunu biliyoruz - ayrıca toplam üsleri 5'e kadar i üssünü artırabileceğimizi de biliyoruz.

Siz deisize edilen tur sayısına gelene kadar böyle devam edersiniz.


Evet öyle. Her tur için bir O (1) işlemi yaparsınız. Bazen turu erken yaparsınız, ama o turu elde ettiğinizde orada yapmak zorunda kalmazsınız, bu yüzden kendi kendine çalışır.
corsiKa

19
(1,1) 'den (4,0)' a nasıl gidiyorsunuz? Lütfen algoritmanızın tam olarak ne olduğunu açıklayın.

Sorun şu ki, sadece iki artımlı olasılığınız yok - örneğin, f(*,2)sadece bunu bulduğunuz için işiniz bitmedi f(a1,b+1)>f(a2,b). Artımlı bir yaklaşım eninde sonunda çıkardığınız bölgeye komşu sınırsız sayıda çift oluşturacaktır.
comingstorm

@ user515430, öğle tatilimde yapabileceğimden daha fazla bir uygulama sağladı, ancak almaya çalıştığım da buydu.
corsiKa

4

Dinamik programlama kullanarak bunu O (n) 'de yapabilirsiniz. Temel gerçek şu ki, i ve j değerlerinin hiçbiri bize 0 veremez ve 1 elde etmek için her iki değerin de 0 olması gerekir;

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

Bu işlevi her aradığınızda, i ve j'nin ayarlanıp ayarlanmadığını kontrol edin, eğer boş değillerse, doldurun TwoCountveFiveCount


C ++ yanıtı. Kötü kodlama stili için üzgünüm, ama acelem var :(

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

Açıkçası, depolama vb. Dinamik olarak artırmak için dizi dışında veri yapıları kullanabilirsiniz. Bu sadece çalıştığını kanıtlamak için bir kroki.


4
Bu ilginç bir cevap gibi görünüyor, ama gerçekten nasıl çalıştığını göremiyorum. Daha fazla ayrıntı ekleyebilir misiniz?
David Brunelle

Kendim okuduktan sonra, nasıl çalıştığını gerçekten göremiyorum. Tamsayı bölümü varsayarsak, 2 için 2 ile tam olarak aynı sonucu verir. Ayrıca, eğer koşullar sıfır olmayan için testler ise, sıfır olmayan girişler olmadığı için asla çalışmaz.
David Thornley

Tüm nay sayers için bir C ++ sürümü gönderildi. @David Yorumlarınız doğru, ancak orijinal kodum yalancı koddu ve komut dosyası terimleriyle düşünüyordum, bu yüzden tamsayı olmayan bir bölünme ve sıfır girişi ile 0 değerinin girişi arasında ayrım
Mikhail

bu kod tüm doğal sayıları numaralandırır, bu nedenle, aşağıdaki "Alabama'da Kayıp" cevabının @ThomasAhle yorumuna göre, dizi sayısını O(exp(sqrt(n)))üretmek gerekir n. Doğrusal algoritma vardır, örneğin ThomasAhle tarafından verildiği gibi.
Ness Ness

1
Haklısın. Anladığım kadarıyla , doğru olmayan basılı öğelerin sayısı değil, son değer O(n)demekti n. İşlevsel dillerin nasıl çalıştığını veya birleştirmenin sabit zamanda nasıl çalıştığını bilmiyorum, ancak cevabı benim oyumu aldı
Mikhail

2

Neden buna başka yönden bakmaya çalışmıyorsunuz? Orijinal formüle karşı olası cevapları test etmek için bir sayaç kullanın. Sahte kod için özür dilerim.

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

Yaklaşık bu çalışır O(4^sqrt(n))çünkü nthdizinin sayısı yaklaşık bu boyuttaki olduğunu.
Thomas Ahle

2

Bu , OEIS'deki ilgili kayıttır.

İlk birkaç terimi oluşturarak sıralı diziyi elde etmek mümkün görünüyor.

1 2 4 5

ve sonra ikinci terimden başlayarak sonraki ikisini elde etmek için 4 ve 5 ile çarpın

1 2 4 5 8 10

1 2 4 5 8 10 16 20

1 2 4 5 8 10 16 20 25

ve bunun gibi...

Sezgisel olarak, bu doğru görünüyor, ancak elbette bir kanıt eksik.


2
Yanlış :( [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 ] Ancak 500 <512 = 2 ^ 9 <625.
GaBorgulya

1
@NateKerkhofs, 512 üretilir, ancak 512 önceden oluşturulmuş 625'ten daha az olduğu için sıra dışıdır; algoritma, çıktıyı sıraya koymak için daha fazla mantığa ihtiyaç duyar. - Bu nedenle algoritma, önerilen algoritma kadar basit değildir ve aynı algoritma değildir.
GordonBGood

1

Log_2 (5) = 2,32 olduğunu biliyorsunuz. Bundan 2 ^ 2 <5 ve 2 ^ 3> 5 olduğuna dikkat çekiyoruz.

Şimdi olası cevapların bir matrisine bakın:

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

Şimdi, bu örnek için, sayıları sırayla seçin. Orada sipariş olurdu:

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

Her satırın, onu başlatan satırın 2 sütun arkasında başladığını unutmayın. Örneğin, i = 0 j = 1 doğrudan i = 2 j = 0'dan sonra gelir.

Dolayısıyla bu modelden türetebileceğimiz bir algoritma (j> i olduğunu varsayalım):

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

NOT: Buradaki kod, i ve j üstlerinin değerlerini 10'dan küçük olacak şekilde kapsar. Bu algoritmayı, diğer rastgele sınırlara sığacak şekilde kolayca genişletebilirsiniz.

NOT: Bu algoritmanın çalışma süresi ilk n cevap için O (n) 'dir.

NOT: Bu algoritma için alan karmaşıklığı O (1) 'dir


"Her satır, başlayan satırın arkasında 2 sütun başlar" yazdınız. Ancak 2 ^ 9 = 512 ve 5 ^ 4 = 625, bu nedenle bu satır 4 için geçerli değildir.
GaBorgulya

@ user678105 Haklısın. Bu kod çalışmıyor. Üzgünüm. Bu kod günlüğün yuvarlanması ve önemli olmadığı varsayımım nedeniyle çalışmıyor.
KLee1

1
Bunu nasıl düzeltebileceğiniz aşağıda açıklanmıştır. İntegral katsayılı noktalarla dolu (x, y) düzleminde, (0,1) ila (log2 (5), 0) arasında bir çizgi çizin. (0,0) sol üst köşede. X ekseni sağa, Y ekseni aşağı gider. Şimdi (0,0) başlangıç ​​noktasından 1. satıra dik olan bir çizgi çizin. Şimdi ilk satırı ikinci, daha ileri ve daha uzağa doğru kaydırın ve tamsayı koordinat noktalarını üzerinden geçerken toplayın. {2,3,5} ile oluşturulan dizi için, (i, j, k) uzayda hareket eden bir düzlem olacaktır. Bu fikri koda çevirebilirseniz, bana bir not verin. :)
Ness Ness

1

Uygulamam aşağıdaki fikirlere dayanmaktadır:

  • Her ikisi de 1 ile başlayan iki Q2 ve Q5 kuyruğu kullanın. Her iki kuyruğu da sıralı tutacağız.
  • Her adımda, en küçük sayı öğesini MIN Q2 veya Q5'ten ayırın ve yazdırın. Hem Q2 hem de Q5 aynı öğeye sahipse - her ikisini de kaldırın. Bu numarayı yazdırın. Bu temelde iki sıralı diziyi birleştirmektir - her adımda en küçük elemanı seçin ve ilerleyin.
  • MIN * 2 ila Q2 ve MIN * 5 ila Q5 değerlerini sıkın. MIN, önceki MIN numarasından daha yüksek olduğu için, bu değişiklik Q2 / Q5 değişmezinin sıralanmasını bozmaz.

Misal:

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'da kod:

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

sonuçlarını hesaplamak ve değerleri ile birlikte, sıralı bir liste halinde koymak ivej


Bu muhtemelen dizinin ilerleyen ucunda delikler açacaktır. Örneğin sahip olacaksınız 2^n*5^nama 2^(n+1)*5^(n-1)hangisi daha küçük değil .
Thomas Ahle

@Thomas Burada mantığınızı takip ettiğimden emin değilim. Birini hesaplarsanız, neden diğerini de hesaplamasınız ki?
vlad

2
@vlad i's ve s'leriniz için bir sınırınız olmalı j, değil mi? Aksi takdirde hiçbir zaman sıralama durumuna geçemezsiniz ve dolayısıyla hiçbir zaman tek bir değer döndürmezsiniz. Ancak nseçtiğiniz herhangi bir sınır için listeniz hatalı olacaktır.
Thomas Ahle

Bu argümanınız hala mantıklı değil. OP hiçbir zaman sonuç listesine bir son vermedi. Eğer yaparsa, max ive j.
vlad

1
@vlad Cevabınızı okurken, önce "sonuçları" / 2^i*5^jdeğerleri hesaplar ve sonra sıralarsınız. Sınırlı sayıda "sonucunuz" yoksa, sıralama adımına nasıl ulaşırsınız?
Thomas Ahle

0

User515430 tarafından Edsger Dijkstra tarafından uygulanan algoritma (http://www.cs.utexas.edu/users/EWD/ewd07xx/EWD792.PDF) muhtemelen alabileceğiniz kadar hızlıdır. 2^i * 5^j"Özel numara" biçimindeki her numarayı ararım . Şimdi vlads cevap olacaktır O(i*j)ama bir çift algoritma ile, biri özel sayılar üretmek için O(i*j)ve diğeri onları sıralamak için (bağlantılı makaleye göre) O(i*j).

Ama Dijkstra'nın algoritmasını kontrol edelim (aşağıya bakın). Bu durumda n, ürettiğimiz özel sayıların miktarı eşittir i*j. Bir kez 1 -> ndöngü yapıyoruz ve her döngüde sabit bir eylem gerçekleştiriyoruz. Yani bu algoritma da öyle O(i*j). Ve oldukça parlak bir hızlı sabit ile.

GMP (C ++ sarmalayıcı) ve bağımlılık ile C ++ benim uygulama boost::lexical_cast, ancak kolayca kaldırılabilir (tembel değilim ve kim Boost kullanmaz?). İle derlendi g++ -O3 test.cpp -lgmpxx -o test. Q6600 üzerinde Ubuntu 10.10 time ./test 1000000verir 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

Satır olarak i ve sütun olarak j ile bir matris çizerseniz, deseni görebilirsiniz. İ = 0 ile başlayın ve sonra matrisin tepesine ulaşıncaya kadar 2 satır ve sağ 1 sütun yukarı gidip matrisi hareket ettirin (j> = 0). O zaman git i + 1, vb ...

Yani i = 7 için şu şekilde seyahat edersiniz:

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

Ve i = 8 için:

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

Burada Java'da i = 9'a kadar gidiyor. Matris konumunu (i, j) ve değeri yazdırır.

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

Sezgim :

Başlangıç ​​değerini 1 olarak alırsam, burada i = 0, j = 0 ise, sonraki sayıları (2 ^ 1) (5 ^ 0), (2 ^ 2) (5 ^ 0), (2 ^ 0) olarak oluşturabilirim * (5 ^ 1), ... yani 2,4,5 ..

Diyelim ki herhangi bir noktada numaram x. sonraki sayıları aşağıdaki yollarla oluşturabilirim:

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

Açıklama :

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 sürüşü

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 ile başlayalım.

    Sonraki üç sayı 1 * 2, 1 * 4, 1 * 5 [2,4,5]; [1,2,4,5] arr

  • Şimdi x = 2

    Sonraki üç sayı [4,8,10] {4 zaten gerçekleştiğinden beri görmezden geleceğiz} [8,10]; [1,2,4,5,8,10] arr

  • Şimdi x = 4

    Sonraki üç sayı [8,16,20] {8 zaten görmezden geldi} [16,20] Arr [1,2,4,5,8,10,16,20]

  • x = 5

    Sonraki üç sayıya [10,20,25] {10,20} zaten [25] eklenmiştir Arr [1,2,4,5,8,10,16,20,25]

Fesih Koşulu

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

analiz

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

0

Gelecek hafta ne olacağını merak ediyordum ve bu soruyu buldum.

Bence, fikir 2 ^ i 5 ^ j gibi büyük adımlarda değil. Bir sonraki j adımı daha büyük olmayacağı sürece i'yi artırın.

C ++ 'daki örnek (Qt isteğe bağlıdır):

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

    }
}

Çıktı:

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

Bu çözüm bazı kombinasyonları kaçırıyor. Örneğin, i = 1, j = 2 olduğu durumda, bu durumda i = 1 ve j> 1 olduğu durumu incelemez ..
Federico

@Federico: Haklısın! Neden 6 yıllık aralıklarla iki kez google-röportajlarında başarısız olduğumu merak
etmiyorum

0

İşte benim çözümüm

#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 */
 }

Sonuç:

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

Muhtemelen yanıldığımı biliyorum ama 2,3,5 gibi çok sayı içermediğinden burada çok basit bir sezgisel tarama var. Herhangi bir i için, j 2 ^ i * 5 ^ j sonraki dizinin 2 ^ (i-2) * 5 ^ (j + 1) olacağını biliyoruz. Google q olmak için basit bir çözüm olması gerekir.

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

Bu çıktıyı şu şekilde üretir:

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 veya 200'e kadar çalışabilir, ancak bir noktada bazı sayıları atlamaya ve / veya yanlış sırada çıkmaya başlar.
Ness Ness

0

İfadede i veya j değerini artırdığımızda gerçekte olana 2^i * 5^jbakarsanız, 2 veya başka bir 5 ile çarpıyorsunuz. Sorunu - i ve j'nin belirli bir değeri göz önüne alındığında, bir sonrakini nasıl bulursunuz daha fazla değer, çözüm görünür hale gelir.

İşte oldukça sezgisel olarak numaralandırabileceğimiz kurallar:

  • i > 1İfadede bir çift 2s ( ) varsa, bir sonraki en büyük sayıyı elde etmek için bunları 5 ile değiştirmeliyiz. Böylece i -= 2ve j += 1.
  • Aksi takdirde, 5 ( j > 0) varsa, bunu üç 2s ile değiştirmeliyiz. Yani j -= 1ve i += 3.
  • Aksi takdirde, değeri en aza indirmek için sadece 2 tane daha sağlamamız gerekir. i += 1.

İşte Ruby'deki program:

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

'İ' asla 4'ten büyük olmadığından çalışmaz, bu nedenle 32'nin (2 ^ 5) katları görünmez.
threenplusone

0

Java Collection kullanmamıza izin verilirse bu sayıyı O (n ^ 2) olarak alabiliriz

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

Burada powerLimit çok dikkatli bir şekilde başlatılmalıdır !! İstediğiniz sayıya bağlı olarak.


bu yanlış sonuçlar verir: 2 ^ 6 * 5 = 320'den önce 2 ^ 8 = 256 eksik. numaralandırma alanı dikdörtgen değil üçgen şeklindedir.
Ness Ness

@WillNess Nasıl ?? PowerLimit = 9 ayarladığımda, bu snippet aşağıdaki sayıları döndürür 1 2 4 5 8 10 16 20 25 32 40 50 64 80 100 125
128160200250220320400500

hayır, 100 sayı üretir. nerede duracağını nereden biliyorsun? bunu açıklamalısın. --- Kod snippet'inizde 7 olarak bahsetmiştim. Bunun geçerli bir cevap olması için, belirli bir sayı için limiti nasıl ayarlayacağınızı ve kaç tane fazla üreteceğini açıklamanız gerekir .
Ness Ness

0

İşte Scala ile olan girişimim:

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

Çıktı:

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)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.