Wyszedłeś lekko, prawdopodobnie nie chcesz pracować dla funduszu hedgingowego, w którym kwanty nie rozumieją podstawowych algorytmów :-)
Nie ma sposobu na przetworzenie struktury danych o dowolnej wielkości w programieO(1)
jeśli tak jak w tym przypadku, każdy element trzeba odwiedzić co najmniej raz. Najlepiej można liczyć to O(n)
w tym przypadku, gdzie n
jest długością łańcucha.
Chociaż, na marginesie, nominalny O(n)
algorytm będzie mieć O(1)
za stałej wielkości wejściowych tak, technicznie, mogą być tutaj poprawne. Jednak zwykle nie jest to sposób, w jaki ludzie używają analizy złożoności.
Wydaje mi się, że mogłeś zrobić na nich wrażenie na wiele sposobów.
Po pierwsze, informując ich, że tak nie można tego zrobić O(1)
, chyba że użyjesz powyższego rozumowania „podejrzanego”.
Po drugie, pokazując swoje elitarne umiejętności, dostarczając kod Pythonic, taki jak:
inpStr = '123412345123456'
# O(1) array creation.
freq = [0] * 1000
# O(n) string processing.
for val in [int(inpStr[pos:pos+3]) for pos in range(len(inpStr) - 2)]:
freq[val] += 1
# O(1) output of relevant array values.
print ([(num, freq[num]) for num in range(1000) if freq[num] > 1])
To daje:
[(123, 3), (234, 3), (345, 2)]
chociaż możesz oczywiście zmienić format wyjściowy na dowolny.
I wreszcie, mówiąc im, że prawie na pewno nie ma problemu z plikiemO(n)
rozwiązaniem, ponieważ powyższy kod dostarcza wyniki dla jednomilionowego ciągu w znacznie mniej niż pół sekundy. Wydaje się, że skaluje się również dość liniowo, ponieważ ciąg 10 000 000 znaków zajmuje 3,5 sekundy, a 100 000 000 - 36 sekund.
A jeśli potrzebują czegoś więcej, istnieją sposoby na zrównoleglenie tego rodzaju rzeczy, które mogą znacznie przyspieszyć ten proces.
Oczywiście nie w obrębie jednego interpretera Pythona, ze względu na GIL, ale możesz podzielić ciąg na coś podobnego (nakładanie się vv
jest wymagane, aby umożliwić prawidłowe przetwarzanie obszarów granicznych):
vv
123412 vv
123451
5123456
Możesz je wyhodować, aby oddzielić pracowników, a następnie połączyć wyniki.
Dzielenie danych wejściowych i łączenie danych wyjściowych prawdopodobnie zatopi wszelkie oszczędności małymi ciągami (a być może nawet milionami cyfr), ale w przypadku znacznie większych zestawów danych może to mieć znaczenie. Oczywiście obowiązuje tutaj moja zwykła mantra „mierzyć, nie zgaduj” .
Ta mantra odnosi się również do innych możliwości, takich jak całkowite obejście Pythona i użycie innego języka, który może być szybszy.
Na przykład, następujący kod C, działa na tym samym sprzęcie, co wcześniej kodu Pythona, obsługuje 100 mln cyfr w 0,6 sekundy, z grubsza taką samą ilość czasu jak kod Python przetworzonego jednego miliona. Innymi słowy, znacznie szybciej:
#include <stdio.h>
#include <string.h>
int main(void) {
static char inpStr[100000000+1];
static int freq[1000];
// Set up test data.
memset(inpStr, '1', sizeof(inpStr));
inpStr[sizeof(inpStr)-1] = '\0';
// Need at least three digits to do anything useful.
if (strlen(inpStr) <= 2) return 0;
// Get initial feed from first two digits, process others.
int val = (inpStr[0] - '0') * 10 + inpStr[1] - '0';
char *inpPtr = &(inpStr[2]);
while (*inpPtr != '\0') {
// Remove hundreds, add next digit as units, adjust table.
val = (val % 100) * 10 + *inpPtr++ - '0';
freq[val]++;
}
// Output (relevant part of) table.
for (int i = 0; i < 1000; ++i)
if (freq[i] > 1)
printf("%3d -> %d\n", i, freq[i]);
return 0;
}