hoppke@gmail.com


Ćwiczenie programistyczne

Wpis na 0. poziomie, wysłany 13 stycznia 2010 o 22:32:45

W trakcie rozglądania się za nową, ciekawą pracą otrzymałem do rozwiązania dość nietypowe (jak na procesy rekrutacyjne) zadanie. Rozwiązywanie go było dość ciekawe, więc pomyślałem, że się podzielę:

LTP (Left-Truncatable Prime) to liczba pierwsza , która

  • nie zawiera cyfry 0
  • pozostaje liczbą pierwszą po odcięciu dowolnej ciągłej sekwencji cyfr z lewej strony.

Wprowadzenie:
5167 to LTP, gdyż 5167, 167, 67 i 7 są liczbami pierwszymi; 2179 nie jest LTP, bo co prawda 2179, 179 i 79 są liczbami pierwszymi, ale 9 już nie. W przedziale do 1 000 000 000 znajduje się 2166 LTP.

Napisz program, który:

  1. przyjmuje pojedynczą liczbę n (1 ≤ n ≤ 2166) jako parametr CLI
  2. oblicza n-tą liczbę LTP
  3. wypisuje wartość tej liczby na standardowe wyjście

Na przykład:

  1. podanie 10 powinno wypisać 47
  2. podanie 100 powinno wypisać 5167
  3. podanie 1000 powinno wypisać 8391283

Twoje rozwiązanie powinno mieć na uwadze wydajność (choć nie tylko ten aspekt wymaga uwagi). Twój program powinien być w stanie zwrócić odpowiedź w przeciągu 500ms na standardowym PC.

Oprócz tego oryginalne zadanie sugerowało, że rozwiązanie powinno być jakości "produkcyjnej", a stworzenie go nie powinno zająć więcej niż 1h, ale możemy to sobie darować.

Mnie najbardziej interesuje: jakie, droga braci techniczna, masz pomysły na algorytm, i ile czasu/MB pamięci potrzebują wasze rozwiązania? Zaznaczam, że program ma liczby obliczać, więc rozwiązanie typu "ściągam listę LTP z internetu, zapisuję w pliku, a program to tylko wczytuje" jest niekoszerne (taki był mój pierwszy pomysł :)

A, usłyszałem też, że nawet programiści z wieloletnim doświadczeniem potrafią mieć problemy z rozwiązaniem tego zadania/zapewnieniem odpowiedniej wydajności.


Komentarze do notki Ćwiczenie programistyczne

  1. h

    13 stycznia 2010 o 22:44:18

    zaczynamy od 2,3,5,7

    mnożymy * 10, i szukamy liczb pierwszych 21-29, 31-39, 51-59, 71-79
    (oczywiście liczby parzyste możemy sobie darować :>)

    po znalezieniu mnożym je dalej * 10, i szukamy dalej dopóki nie znajdziemy N liczb LTP.

    Chyba tak.

  2. 13 stycznia 2010 o 22:49:05

    Czyli de facto gubisz np 13 i 17...

  3. h

    13 stycznia 2010 o 22:56:01

    Ano gubię :)
    Dzięki.

  4. 13 stycznia 2010 o 23:33:06

    Zadanie ładnie opisać, zrobić zbiór testowy i wrzucić na SPOJ-a ;p

  5. 13 stycznia 2010 o 23:40:42

    Hm. A może tak? Bierzemy przedział liczbowy i traktujemy go sitem Eratostenesa z tym, że każde "oczko" przed wrzuceniem do tablicy testujemy pod kątem bycia LTP, czyli skanowania tablicy już istniejących LTP pod kątem występowania kolejnych wariantów. Jeśli liczebność tablicy LTP po analizie całego przedziału jest mniejsza od n, bierzemy następny przedział, jeśli nie, przerywamy wcześniej iterację w odpowiednim momencie.

  6. SomeOne

    13 stycznia 2010 o 23:50:14

    Mój pomysł:
    Mam sobie kopiec z minimum na początku.
    Na dzień dobry wrzucam sobie do niego 2,3,5,7.
    Teraz idę sobie pętelką ściągając liczbę z góry i:
    * doklejam z lewej strony cyfry 1 - 9 i sprawdzam czy liczba jest pierwsza(na przykład lekkim brutem do pierwiastka) jeśli jest to wrzucam ją na kopiec.
    * A i z każdym przebiegiem pętli zliczam na której LTP się znajduje. Jak dojdę do szukanej to ją zwracam.
    To tak na szybko - chyba działa.
    Złożonościowo to chyba wychodzi tak:
    * Kopiec to jakieś O(nlogn).
    * sprawdzanie pierwszości pseudo brutem to maksymalnie sqrt(10^9) ~ 32000
    czyli w sumie złożoność to jakieś O(x
    sqrt(n)*logx)

    A pamięć to O(n) - tylko kopiec jest potrzebny.

  7. 13 stycznia 2010 o 23:51:44

    SomeOne: zgubiles 19tke

  8. SomeOne

    13 stycznia 2010 o 23:53:45

    9 nie jest pierwsze chyba? czy już powinienem iść spać ;P?
    9 = 3 * 3 ;)

  9. 14 stycznia 2010 o 00:02:49

    @torero: Myślę, że sito Eratostenesa jest nadal o wiele za wolne.

    @SomeOne: Na razie wydaje mi się to jedynym sensownym rozwiązaniem (oprócz znalezienie funkcyjnej zależności n -> LTP). Wydaje mi się jednak, że wystarczy tablica z dwoma wskaźnikami - pierwszy na ostatnią LTP z której udało się utworzyć inną LTP, drugi na ostatnio utworzoną LTP.

  10. 14 stycznia 2010 o 00:08:59

    SomeOne wygrales, nie wczytalem sie dosc dokladnie w Hoppkego

  11. SomeOne

    14 stycznia 2010 o 00:29:08

    Wpadłem jeszcze na taki pomysł że w sumie w tym moim rozwiązaniu za każdym razem w pętli zwiększam rząd wielkości liczby którą biorę z kopca więc może lepsze/szybsze by było zrobić sobie powiedzmy 9 kubełków na liczby rzędu 10^n i zrobić taką pętle po tych kubełkach że biorę z kubełka 10^k i tworze liczby do kubełka 10^(k+1)... w sumie zyskam na tym chyba logn(zostanie mi n*sqrt(n)) jeśli dobrze się to zaimplementuje(tak żeby dodawać do kubełków w odpowiedniej kolejności)...

  12. 14 stycznia 2010 o 00:51:13

    Sito nie wyrabia, trza zrobić tak jak mówi h tylko, że dokładnie na odwrót. ;) Tzn. zaczynamy od 2, 3, 5, 7 i sprawdzamy czy 12, 13, 15, 17, 22, 23, 25, 27, ..., 97 są pierwsze. Potem analogicznie doklejamy cyfrę na początku dwucyfrowych liczb, trzycfyrowych itd.

  13. 14 stycznia 2010 o 00:55:25

    Kopiec jest zbędny, wystarczy tylko tak jak pisze SomeOne podział na "kubełki" odpowiadające długości cyfry (przy czym kubełki implementujemy na pojedynczej tablicy operując w sumie na 4 indeksach: początek kubełka, koniec kubełka, ostatnia dodana liczba oraz aktualnie rozpatrywana liczba dla pętli doklejającej z lewej cyfrę).

  14. iLLuSiONiSt

    14 stycznia 2010 o 01:21:09

    Problem jest ciekawy. Czytając komentarze dotychczas, warto zauważyć parę rzeczy:
    - 1 nie jest liczbą pierwszą
    - 2 jest jedyną liczbą parzystą, która jest pierwsza
    - 5 jest jedyną "wielokrotnością" samej siebie, która jest pierwsza
    - 9 nie jest pierwsza

    Zatem wyłączając spośród wszystkich cyfr, cyfry parzyste oraz 1, 5 i 9, pozostają nam 3 i 7.

    Moją sugestią jest wygenerowanie liczb postaci n10 + 3 oraz n10 + 7 i sprawdzenie, czy każda z wygenerowanych liczb jest podzielna przez 3 lub 7.

    Oczywiście rozwiązanie nie jest doskonałe, ale myślę, że gdzieś dalej można z tym dojść. :)

  15. iLLuSiONiSt

    14 stycznia 2010 o 01:23:59

    Tak w ramach dokładności, mówię o liczbach (n x 10) + 3 oraz (n x 10) + 7. Jeśli taka liczba jest podzielna przez 3 lub 7, to naturalną koleją rzeczy nie jest pierwsza.

  16. 14 stycznia 2010 o 01:44:43

    143 = 11 * 13

    Co więcej, samo sprawdzenie czy są podzielne przeze 3 i 7 nie wystarcza -- trzeba jeszcze sprawdzić czy są to LTP.

    Co więcej, wydaje mi się, że podchodząc w ten sposób do sprawy przeszukuje się o wiele więcej liczb. Przykładowo jest 11 dwucyfrowych LTP zatem stosując metodę opisaną przeze mnie przeszukamy "tylko" 99 cyfr trzycyfrowych, gdy tymczasem w Twoim dwa razy tyle. Dla większych liczb ta dysproporcja będzie się dodatkowo powiększać.

  17. iLLuSiONiSt

    14 stycznia 2010 o 01:46:24

    Fakt, my bad.

  18. mig

    14 stycznia 2010 o 04:18:25

    Uwaga, spojler ;-)
    http://ideone.com/sgnQANUy
    Nie czytałem komentarzy powyżej, więc rozwiązanie jest autorskie. ;-)
    Algorytm polega na stopniowym rozszerzaniu wykrytych już liczb pierwszych o 1 cyfrę w lewo. Czyli aby sprawdzić liczby n-cyfrowe wstawiam do kolejki wszystkie (n-1)-cyfrowe liczby doklejając im cyfry (1-9) z przodu.
    Następnie testuje wszystkie liczby z kolejki i te z nich które są pierwsze stają się podstawą do następnego rozszerzenia.
    Sam test pierwszości jest najprostszy z możliwych (dzielenie od 2 do sqrt(x)).

  19. 14 stycznia 2010 o 13:17:20

    No czyli to co już żeśmy wymyślili. ;)

    Swoją drogą jak ja lubię kontenery C++ wykorzystywane wszędzie gdzie się da...

    A skoro już się chwalimy rozwiązaniami: http://pastebin.org/76064

  20. 14 stycznia 2010 o 13:30:06

    Zastanawiam się jeszcze nad jedną sprawą - usprawnieniem sprawdzania czy liczba jest pierwsza. Nie ma sensu sprawdzanie podzielności przez liczby złożone. Może warto na samym początku znaleźć (sitem Eratostenesa) liczby pierwsze mniejsze od pierwiastka z 1000000000 (jest ich 3000 z hakiem), zapisac w jakiejś tablicy i używać do spradzania podzielności.

  21. 14 stycznia 2010 o 13:49:12

    Faktycznie przyśpieszyło jakieś 3 razy: http://pastebin.org/76071

  22. 14 stycznia 2010 o 14:05:24

    ~/> ./a.out
    1000
    8391283
    ~/> ./a.out
    2000
    Błąd w obliczeniach zmiennoprzecinkowych
    ~/> ./a.out
    2166
    Błąd w obliczeniach zmiennoprzecinkowych
    ~/>

  23. Hoppke

    14 stycznia 2010 o 14:16:14

    Super!

    Moje rozwiązanie jest identyczne w założeniach z tym, co SomeOne, mig i mina86 wykombinowali. Dodatkowe punkty lansu dla wszystkich rozwiązań, które uniknęły kodowania na sztywno "startowej listy" liczb pierwszych < 10 :)

    Profilowanie kodu wskaże zapewne, że najwięcej czasu spędza się na sprawdzaniu czy potencjalna LTP (znana LTP z doklejoną na początku cyfrą [1-9]) jest faktycznie liczbą pierwszą. Osobiście wziąłem brute-forca do pierwiastka z n (sprawdziłem nawet, czy szybciej jest sprawdzać w pętli z indeksem rosnącym, czy malejącym), ale kombinowałem też z probabilistycznymi testami (są takie, które nigdy nie zwracają false negatives, więc myślałem, że może robić taki szybki test w paru iteracjach, a jeśli on nie obleje, to potwierdzić brute forcem -- nie dało mi to jednak zysku wydajności. Probabilistyka pewnie pokazałaby pazurki gdyby mielić większe liczby).

    Kombinowałem z podejściem hybrydowym (z sitem), ale wydajność nie skoczyła mi tak jak oczekiwałem, więc je wywaliłem. Możliwe, że skopałem coś w implementacji, po wynikach miny86 wiem, że warto spróbować ponownie. Co prawda większość pseudo-LTP jest podzielna przez 2 i 3 i powinna odpaść bardzo szybko nawet w brute force, ale najwidoczniej na tych bardziej złożonych przykładach się duuużo oszczędza.

    Pod koniec brakowało mi jeszcze trochę wydajności, więc zdobyłem je tanim zagraniem -- liczby pierwsze sprawdzałem w partiach (10^n, 10^n+1...), i w ramach każdej partii sprawdzanie "isPrime" leciało w osobne wątki (limit wątków biegających równolegle == cpuCount+1). Narzut na tworzenie wątków jest spory i kończą się szybko, ale sprawdzanie niektórych liczb brutem trwa na tyle długo, że sumarycznie wychodziłem do przodu już na dwóch rdzeniach). Minus tego podejścia jest taki, że nie można przerwać obliczania partii 10^n dopóki nie spłyną wszystkie wyniki -- bo mogą spływać w losowej kolejności. Więc na ogół oblicza się więcej liczb, niż jest wymagane. No ale mogłem popisać się pisaniem wielowątkowego kodu, a że był to interview o pracę... ;)

    Nie zaimplementowałem też osobnych kubełków dla każdego (10^n), zrobiłem tylko jeden mega-kubeł na wyniki, przez co przygotowywanie "zarodków" do sprawdzania kolejnej partii 10^n+1 trwało dłużej niż musiało. Nie była to jakaś straszna wielkość, ale wg. profilera była to druga najbardziej czasochłonna czynność (po isPrime).

    Dziękuję więc za pomysły (po powrocie do domu wykorzystam je i zobaczę, o ile podbije mi to wydajność), i dzięki za kod w C! (ja robiłem to w... na Joggerze wstyd przyznać ;)

  24. 14 stycznia 2010 o 14:18:10

    A w jakim języku miałeś to zaimplementować? W Perlu udało mi się osiągnąć ledwie ~2.4s dla 2166, przy < 0.1s dla kodu w C++.

  25. mkay

    14 stycznia 2010 o 14:19:48

    witam,
    napisalem sobie taki sofcik dla zabawy (jakies 5min myslenia i 20 kodowania, a w zasadzie jestem bardziej adminem, niz programista...;>).
    w kazdym badz razie czegos chyba nie rozumiem:
    <mkay@benek>/tmp: ./ltp 1
    1
    <mkay@benek>/tmp: ./ltp 2
    2
    <mkay@benek>/tmp: ./ltp 3
    3
    <mkay@benek>/tmp: ./ltp 4
    5
    <mkay@benek>/tmp: ./ltp 5
    7
    <mkay@benek>/tmp: ./ltp 6
    11
    <mkay@benek>/tmp: ./ltp 7
    13
    <mkay@benek>/tmp: ./ltp 8
    17
    <mkay@benek>/tmp: ./ltp 9
    23
    <mkay@benek>/tmp: ./ltp 10
    31
    <mkay@benek>/tmp: ./ltp 11
    37

    10ta liczba powinna byc =47 (wedlug tresci zadania), zatem ktore z moich liczb nie spelniaja warunkow? (nawet pomijajac 1, to 10ta bedzie =37)

  26. 14 stycznia 2010 o 14:21:00

    Poprawione: http://pastebin.org/76075, zapomniałem, że nie wystarczy wyszukać liczb pierwszych <= sqrt(1e9), ale należy znaleźć pierwszą taką liczbę pierwszą, że jest ona >= sqrt(1e9)

  27. matekm

    14 stycznia 2010 o 14:22:40

    @mkay: 1 nie jest liczba pierwsza.

  28. Hoppke

    14 stycznia 2010 o 14:23:07

    @sawer: tym podobnym do C#, tylko starszym i biegającym w JVM ;)

    @mkay: 1 nie jest pierwsza, a 11 nie jest LTP (bo po obcięciu zamienia się w 1, która nie jest pierwsza).

    Lista: http://users.skynet.be/worldofnumbers/truncat.htm

  29. 14 stycznia 2010 o 14:24:43

    Rozważałem nie hardkodowanie listy liczb pierwszych < 10, ale doszedłem do wniosku, że szkoda zachodu, a ponadto można zastosować wówczas mniej optymalizacji i ogólnie kod przez to staje się trochę bardziej skomplikowany, a nie ma z tego porzytku..

  30. mkay

    14 stycznia 2010 o 14:28:23

    faktycznie - co prawda zastanawialem sie nad 1, ale jakos nie pomyslalem, ze dopuszczajac ja, dopuszczam tez 11, 31 itd. po wyeliminowanie 1 dziala ok;)

  31. Hoppke

    14 stycznia 2010 o 14:29:57

    No, ja po prostu starałem się tego uniknąć, bo treść zadania mówiła o "obliczaniu" liczb. Gdyby nie to "obliczanie", to autentycznie bym oddał kod używający listy wczytywanej z pliku, bo tak bym to zrobił w produkcji i IMO tak jest najsensowniej -- znasz zakres, znasz liczbę wyników (małą), wiesz że są niezmienne... Ale że program miał "liczyć", to bałem się, że kodowanie na stałe liczb <10 zostanie uznane za niekoszerne (miałem problem z ustaleniem granicy "do ilu liczb mogę zakodować na stałe?").

    BTW, jestem ciekaw jak blisko uda mi się z Javą podejść do tego, co zrobiliście w C...

  32. 14 stycznia 2010 o 15:36:38

    rozwiązanie funkcyjnie, się pochwalę :D http://gist.github.com/277205

  33. 14 stycznia 2010 o 15:42:32

    Mojej implementacji w Pythonie obliczenie 2166 liczby zajmuje ~2.4s (podobnie jak implementacja w Perlu), w Javie ~0.2s (w C++ ~0.1s)

  34. 14 stycznia 2010 o 15:49:58

    Na jakiej maszynie? (i jakim kompilatorem C++?)

  35. 14 stycznia 2010 o 15:57:20

    Phi... ja na maszynie wirtualnej (VMWare) mam wynik 0.04. ;)

  36. 14 stycznia 2010 o 16:01:31

    Intel Core 2 Duo P7370 2GHz, 4GB RAM-u, g++ 4.4.1. Sprzęt trudno nazwać standardowym PC, więc nie mam się co chwalić. Chciałem raczej zobaczyć jakie są różnice między praktycznie tym samym kodem w różnych językach.

  37. 14 stycznia 2010 o 17:01:03

    Przypomniało mi się, że przy testowaniu kodu w javie zauważyłem coś ciekawego (tzn. powininem się był spodziewać, ale i tak mnie na chwilę zatkało). Mianowicie miałem w teście jednostkowym kilka różnych wariantów do sprawdzenia -- wyciągnij i sprawdź wartość dziesiątej liczby, setnej liczby, tysięcznej, ostatniej, ostatniej+1..., sprawdzając czas wykonywania i obsługę błędów.

    I chociaż test tworzył za każdym razem całkowicie nową instancję obiektu (takie wymagania w końcu), to każdy kolejny test potrzebował znacząco mniej czasu niż jego poprzednik. Sunowska maszyna wirtualna (1.6 pod Windows, na domyślnych ustawieniach) najprawdopodobniej optymalizowała kod w locie, na podstawie danych zebranych w poprzednich przebiegach.

    sawer, możesz zobaczyć, czy jeśli zapętlisz tworzenie swojego javowego obiektu i wyciąganie z niego pojedynczej wartości 10 razy, to sumaryczny czas też wychodzi Ci dużo niższy niż wynikałoby z przemnożenia czasu pojedynczego przebiegu razy 10? Jeśli jestem niejasny, to chodziło mi o coś w stylu
    for (int i =0; i<10; i++) {
    new LtpGenerator().getNthLtp(2166)
    }

  38. ProgramistaBezDoswiadczenia!

    14 stycznia 2010 o 17:51:32

    include <cstdio>

    include <vector>

    using namespace std;

    define VAR(v, n) typeof(n) v = (n)

    define FOREACH(i, c) for(VAR(i, (c).begin()); i != (c).end(); ++i)

    int k, q, dt, t[2500];
    vector<int> v[10];

    bool MaR(long long x, long long n) {
    if(x>=n) return 0;

    long long d=1, y;
    int t=0, l=n-1;

    while(!(l&1)) { ++t; l>>=1; }

    for(; l>0 || t--; l>>=1) {
    if(l&1) d=(d*x)%n;
    if(!l) { x=d; l=-1; }

    y=(x*x)%n;
    if(y==1 && x!=1 && x!=n-1) return 1;
    x=y;
    

    }

    return x!=1;
    }

    bool IsPrime(int x) { return !(x<2 || MaR(2,x) || MaR(3,x) || MaR(5,x) || MaR(7,x)); }

    inline void Add(int x, int k) { v[k].push_back(x); t[++dt]=x; }

    int main() {

    q=1;
    for(int i=1; i<=9; ++i) {
    for(int x=1; x<=9; ++x)
    if(i==1 && IsPrime(x)) Add(x,1);
    else
    if(i>1) {
    FOREACH(it, v[i-1]) {
    k = x*q + *it;
    if(IsPrime(k)) Add(k,i);
    }
    }

    q*=10;
    

    }

    while(scanf("%d", &q)!=EOF) printf("%d\n", t[q]);

    return 0;
    }

    test pierwszości jest dość niestandardowy- ale sensowne sito Eratostenesa w zupełności wystarcza...
    pozdro!

  39. 14 stycznia 2010 o 17:56:11

    coś się rozjechało - wklejam raz jeszcze...

  40. 14 stycznia 2010 o 18:53:56

    O rany. Albo jestem odzwyczajony od C, albo powyższy kod jest bardzo write-only :)

  41. 14 stycznia 2010 o 19:29:28

    Uff... Myślałem, że tylko ja jestem taki niekumaty... Czy autor zechciałby się nieco rozwieść nad swoim rozwiązaniem?

  42. 14 stycznia 2010 o 19:52:47

    funkcja IsPrime to test pierwszości Millera-Rabina! (http://pl.wikipedia.org/wiki/Test_Millera-Rabina) - zwykłe sito oczywiście też zadziała, ale będzie mniej wydajne. (w obecnej wersji wyliczenia trawają 0.04sec na słabym kompie)

    reszta to takie trochę rekurencyjne podejście: zał. że mamy wyliczone wszystkie LTP długości n-1. Aby wyznaczyć LTP o dł. n, wystarczy "dokleić" pojedynczą cyfrę z lewej strony i sprawdzić, czy otrzymana liczba jest pierwsza!

  43. 15 stycznia 2010 o 16:35:11

    Millera-Rabina zauważyłem (sam jak pisałem robiłem podejście do rozwiązań probabilistycznych), ale zabrałem się za to od złej strony -- założyłem, że skoro algorytm jest probabilistyczny, to muszę i tak zawsze poprawić brute forcem żeby mieć 100% pewność, no i zafiksowałem się bardziej na Sollovay-Strassenie bez należytego zgłębienia innych metod. Nie zauważyłem, że M-R ma parę fajnych właściwości :) W tym zakresie chyba nawet nie musisz sprawdzać z 7, wystarczy 2,3,5(?), więc potencjalnie jeszcze ociupinkę czasu wykonywania się da urwać. Świetne rozwiązanie.

    Pętla do tworzenia kandydatów LTP też wygląda nieźle, chociaż trochę ciężko mi się ją czyta (może przez porozbijanie na kawałki i makra, nie jestem przyzwyczajony do C -- parę komentarzy w kodzie by mi się przydało).

    Anyway, niiiice. I podkradnę pomysł z M-R, dzięki :)

  44. ProgramistaBezDoswiadczenia!

    16 stycznia 2010 o 01:30:48

    czy to oznacza, że zostałem przyjęty? Ah!, dziękuję! :p

    przy okazji warto zaznaczyć, że funkcja MaR, nie jest moja: "Algorytmika praktyczna", Piotr Stańczyk (swoją drogą- świetna pozycja!)

  45. 16 stycznia 2010 o 01:32:51

    Wybacz szczerość, ale osobiście widząc taki kod zastanowiłbym się dwa razy...

  46. Hoppke

    16 stycznia 2010 o 13:29:13

    Nie wiem jakie standardy panują wśród programistów C, z punktu widzenia javowca to był write-only code (prawie jak perlgolf). Produkcyjne to to nie jest (koszt utrzymywania jest zbyt wysoki, nie ma obsługi błędów, jako jedyny chyba też ), ale użyte rozwiązania wyglądają na bardzo efektywne (runtime).

  47. 16 stycznia 2010 o 14:31:15

    Standardy takie jak wszędzie (choć w Javie podnieśli to do ekstremów). Wystarczy tymczasem pozmieniać troszkę nazwy, aby kod był znacznie czytelniejszy: https://gist.github.com/278819/25471489380195d06c664be1b1289c4a8ca666b6.

  48. 16 stycznia 2010 o 18:17:43

    Chyba mi się nudzi... Gdyby ktoś chciał wersję wielowątkową: http://gist.github.com/278819/28b32a472e82cc3f1a88c0e93d16036390664e94

  49. Szymon

    07 kwietnia 2010 o 12:02:24

    Hoppke, mogłeś dać linka do źródła całej zabawy...
    znaczy się pod koniec zeszłego roku popularny
    był wpis:
    http://www.trelford.com/blog/post/C2b2b-vs-C-vs-F-vs-Haskell.aspx

  50. 11 lipca 2010 o 13:00:13

    @Szymon: a o tym nie wiedziałem. Jak napisałem, zadanko to dostałem w trakcie procesu rekrutacyjnego i był to mój pierwszy kontakt z problemem wyszukiwania LTP.

    Chociaż w sumie powinienem był podejrzewać, że jak każde ambitniejsze pytanie rekrutacyjne zostało to pewnie skądś zerżnięte :)

  51. 20 lutego 2011 o 23:41:27

    Na jakie stanowisko się rekrutujesz? Gdzie dają takie zadania?

  52. Hoppke

    21 lutego 2011 o 21:54:28

    Stanowisko? Najróżniejsze, na ogół różne kombinacje słów "developer", "programmer", "senior" i "java". Moje najulubieńsze do tej pory było "senior r&d developer", a najdrętwiejsze to "associate".

    A to konkretne było z rozmowy z jakimś startupem (nazwy nie pamiętam, nie wiem czy coś im wypaliło).

Dodaj komentarz: