Você saiu de ânimo leve, provavelmente não quer trabalhar para um fundo de hedge onde os quantos não entendem algoritmos básicos :-)
Não há como processar uma estrutura de dados de tamanho arbitrário O(1)
se, como neste caso, você precisar visitar todos os elementos pelo menos uma vez. O melhor que você pode esperar é O(n)
, neste caso, onde n
está o comprimento da string.
Embora, como um aparte, uma nominal O(n)
algoritmo vai ser O(1)
para um tamanho de entrada fixa assim, tecnicamente, eles podem ter sido correto aqui. No entanto, geralmente não é assim que as pessoas usam a análise de complexidade.
Parece-me que você poderia tê-los impressionado de várias maneiras.
Primeiro, informando-lhes que é não possível fazê-lo em O(1)
, a menos que você use o "suspeito" fundamentação apresentada acima.
Segundo, mostrando suas habilidades de elite, fornecendo código Pythonic, como:
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])
Isso gera:
[(123, 3), (234, 3), (345, 2)]
embora você possa, é claro, modificar o formato de saída para o que desejar.
E, finalmente, dizendo a eles que quase certamente não há problema com uma O(n)
solução, pois o código acima fornece resultados para uma sequência de um milhão de dígitos em menos de meio segundo. Também parece ter uma escala linear, pois uma sequência de 10.000.000 caracteres leva 3,5 segundos e uma sequência de 100.000.000 caracteres leva 36 segundos.
E, se eles precisarem melhor do que isso, existem maneiras de paralelizar esse tipo de coisa que pode acelerar muito.
Evidentemente, não dentro de um único intérprete Python, devido ao GIL, mas você pode dividir a string em algo como (sobreposição indicada por vv
é necessária para permitir o processamento adequado das áreas de fronteira):
vv
123412 vv
123451
5123456
Você pode cultivá-las para separar os trabalhadores e combinar os resultados posteriormente.
A divisão da entrada e a combinação da saída provavelmente inundarão qualquer economia com pequenas cadeias (e possivelmente até milhões de dígitos), mas, para conjuntos de dados muito maiores, pode muito bem fazer a diferença. Meu mantra habitual de "medir, não acho" se aplica aqui, é claro.
Esse mantra também se aplica a outras possibilidades, como ignorar completamente o Python e usar uma linguagem diferente que pode ser mais rápida.
Por exemplo, o código C a seguir, executado no mesmo hardware que o código Python anterior, manipula cem milhões de dígitos em 0,6 segundos, aproximadamente a mesma quantidade de tempo que o código Python processou um milhão. Em outras palavras, muito mais rápido:
#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;
}