Vous êtes descendu légèrement, vous ne voulez probablement pas travailler pour un hedge fund où les quants ne comprennent pas les algorithmes de base :-)
Il n'y a aucun moyen de traiter une structure de données de taille arbitraire O(1)
si, comme dans ce cas, vous devez visiter chaque élément au moins une fois. Le mieux que vous puissiez espérer est O(n)
dans ce cas, où n
est la longueur de la chaîne.
Bien que, en aparté, un nominal O(n)
algorithme sera être O(1)
pour une taille d'entrée fixe donc, techniquement, ils ont eu raison ici. Cependant, ce n'est généralement pas ainsi que les gens utilisent l'analyse de complexité.
Il me semble que vous auriez pu les impressionner de plusieurs façons.
D'abord, en les informant qu'il n'est pas possible de le faire O(1)
, à moins que vous n'utilisiez le raisonnement «suspect» donné ci-dessus.
Deuxièmement, en montrant vos compétences d'élite en fournissant un code pythonique tel que:
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])
Cela produit:
[(123, 3), (234, 3), (345, 2)]
bien que vous puissiez, bien sûr, modifier le format de sortie à tout ce que vous désirez.
Et, enfin, en leur disant qu'il n'y a presque certainement aucun problème avec une O(n)
solution, puisque le code ci-dessus fournit des résultats pour une chaîne d'un million de chiffres en moins d'une demi-seconde. Il semble également être mis à l'échelle de manière assez linéaire, car une chaîne de 10 000 000 de caractères prend 3,5 secondes et une chaîne de 100 000 000 de caractères prend 36 secondes.
Et, s'ils ont besoin de mieux que cela, il existe des moyens de paralléliser ce genre de choses qui peuvent considérablement l'accélérer.
Pas dans un seul interpréteur Python bien sûr, en raison du GIL, mais vous pouvez diviser la chaîne en quelque chose comme (le chevauchement indiqué par vv
est nécessaire pour permettre un traitement approprié des zones de délimitation):
vv
123412 vv
123451
5123456
Vous pouvez les regrouper pour séparer les travailleurs et combiner les résultats par la suite.
Le fractionnement de l'entrée et la combinaison de la sortie sont susceptibles de submerger toute économie avec de petites chaînes (et peut-être même des chaînes à millions de chiffres) mais, pour des ensembles de données beaucoup plus volumineux, cela peut bien faire une différence. Mon mantra habituel de «mesurer, ne pas deviner» s'applique ici, bien sûr.
Ce mantra s'applique également à d' autres possibilités, telles que le contournement de Python et l'utilisation d'un langage différent qui peut être plus rapide.
Par exemple, le code C suivant, exécuté sur le même matériel que le code Python précédent, gère cent millions de chiffres en 0,6 seconde, à peu près le même temps que le code Python en a traité un million. En d'autres termes, beaucoup plus rapide:
#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;
}