Je préfère une approche qui utilise des algorithmes déjà mis en œuvre. Alors que beaucoup d'autres solutions utilisent des divisions récursives par 10
je pense qu'il est préférable d'utiliser les logarithmes à 10 bases, qui ont O(1)
de sorte que la complexité totale de la solution est O(1)
.
Divisons le problème en deux parties.
Premier gérera le cas où la partie number * 10^n
est entre min
y max
pour au moins un n
. Cela nous permettrait de vérifier par exemple si number = 12
y min,max = 11225,13355
que x = 12000 = 12*10^3
est entre min
y max
. Si ce test est positif, cela signifie que le résultat est True
.
Deuxièmement traitera les cas où number
est le début de l'un ou l'autre min
o max
. Par exemple, si number = 12
y min,max = 12325,14555
le premier test échouera, car 12000
n'est pas entre min
y max
(ainsi que tous les autres numéros) 12*10^n
pour tout n
). Mais le deuxième test permettra de constater que 12
est le début de 12325
et retourner True
.
Premier
Vérifions, si le premier x = number*10^n
qui est égal ou supérieur à min
est inférieur ou égal à max
(donc min <= x <= max, where x is number*10^n for any integer n
). Si elle est supérieure à max
que tous les autres x
es seront plus grandes, car nous avons pris les plus petites.
log(number*10^n) > log(min)
log(number) + log(10^n) > log(min)
log(number) + n > log(min)
n > log(min) - log(number)
n > log(min/number)
Pour obtenir le nombre à comparer, il suffit de calculer le premier satisfaisant n
:
n = ceil(log(min/number))
Et calculer alors le nombre x
:
x = number*10^n
Deuxièmement
Nous devons vérifier si notre nombre est un début littéral de l'une ou l'autre limite.
Nous calculons simplement x
commençant par les mêmes chiffres que number
et rembourré avec 0
à l'extrémité, ayant la même longueur que les min
:
magnitude = 10**(floor(log10(min)) - floor(log10(number)))
x = num*magnitude
Et ensuite, vérifiez si min
et x
la différence (en échelle de magnitude) est inférieure à 1
et supérieur ou égal à 0
:
0 <= (min-x)/magnitude < 1
Donc, si number
es 121
y min
es 132125
entonces magnitude
es 1000
, x = number*magnitude
serait 121000
. min - x
donne 132125-121000 = 11125
qui devrait être inférieur à 1000
(autrement min
le début serait plus grand que 121
), nous le comparons donc avec magnitude
en divisant par sa valeur et en comparant à 1
. Et ce n'est pas grave si min
es 121000
mais pas si min
es 122000
c'est pourquoi 0 <=
y < 1
.
Le même algorithme est utilisé pour max
.
Pseudo code
En incorporant tout cela dans un pseudo-code, on obtient cet algorithme :
def check(num,min,max):
# num*10^n is between min and max
#-------------------------------
x = num*10**(ceil(log10(min/num)))
if x>=min and x<=max:
return True
# if num is prefix substring of min
#-------------------------------
magnitude = 10**(floor(log10(min)) - floor(log10(num)))
if 0 <= (min-num*magnitude)/magnitude < 1:
return True
# if num is prefix substring of max
#-------------------------------
magnitude = 10**(floor(log10(max)) - floor(log10(num)))
if 0 <= (max-num*magnitude)/magnitude < 1:
return True
return False
Ce code pourrait être optimisé en évitant les calculs répétés de log10(num)
. De plus, dans la solution finale, je passerais d'une portée flottante à une portée entière ( magnitude = 10**int(floor(log10(max)) - floor(log10(num)))
) et ensuite effectuer toutes les comparaisons sans division, c'est-à-dire 0 <= (max-num*magnitude)/magnitude < 1
-> 0 <= max-num*magnitude < magnitude
. Cela réduirait les risques d'erreurs d'arrondi.
Il est également possible de remplacer magnitude = 10**(floor(log10(min)) - floor(log10(num)))
avec magnitude = 10**(floor(log10(min/num)))
, donde log10
n'est calculé qu'une seule fois. Mais je ne peux pas prouver que cela donnera toujours des résultats corrects, ni le réfuter. Si quelqu'un pouvait le prouver, je lui en serais très reconnaissant.
Tests (en Python) : <a href="http://ideone.com/N5R2j" rel="nofollow noreferrer">http://ideone.com/N5R2j </a>(vous pourriez modifier l'entrée pour ajouter d'autres tests).