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 njest 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ę vvjest 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;
}