40

En una cadena que contiene un número entero, ¿cómo puedo verificar que todos los dígitos son iguales, pero sólo utilizando operaciones matemáticas?.

Por ejemplo, ¿cómo puedo saber que "1111" o "999999" tienen todas sus cifras iguales sin utilizar listas, ni analizarlo como string, ni similares? (Así como también, comprobar que "2222220" no cumple esta verificación).

El análisis debe ser exclusivamente numérico-matemático.


Si fuese a analizarlo como string, simplemente comprobaría en un bucle que el primer caracter es igual a cada uno de los sucesivos. Sin embargo, se me ocurrió que quizás se puede realizar con operaciones sobre el número... ¿Existe alguna forma de hacerlo?

sstan
  • 16,591
  • 2
  • 21
  • 45
Facu Arg
  • 551
  • 1
  • 5
  • 6

11 Answers11

63

La respuesta de ChemaCortes es correcta y la forma simple de hacerlo, como dices:

El análisis debe ser exclusivamente numérico-matemático

yo lo he complicado un poquito más para solucionarlo sin usar ningún ciclo, usando algunas propiedades matemáticas, el código sería el siguiente:

from math import log10

def digitos_iguales(num):
    return num == 0 or num % ((10**int(log10(abs(num))+1) - 1) // 9) == 0

El razonamiento matemático es el siguiente:

Si un número entero tiene todos los dígitos iguales, entonces ese número dividido entre uno de sus dígitos es igual al entero con el mismo número de dígitos, pero siendo todos ellos 1.

Por ejemplo:

44544/4 = 11136
44444/4 = 11111

De lo anterior es fácil deducir que:

Todo número que tiene todos sus dígitos iguales es divisible entre el número de igual cantidad de dígitos pero en el que todos sus ellos son 1.

Esto quiere decir que el resto de la división entre ambos (módulo) es 0:

>>> 44444 % 11111 = 0
>>> 44844 % 11111 = 400

Por lo tanto, nuestro problema se reduce a obtener el entero correspondiente que tiene la misma cantidad de dígitos que nuestro número, pero en el que todos ellos son 1.

Estos números (1, 11, 111, 1111, 11111, 111111, etc) forman una secuencia que podemos ver aquí y que responde a una fórmula sencilla:

f(n) = (10^n - 1) / 9

Donde n es el numero de dígitos.

Por ejemplo el número de esta secuencia con 5 dígitos es:

 f(5) = (10^5 - 1) / 9
 f(5) = (100000 - 1) / 9
 f(5) = (99999) / 9
 f(5) = 11111

Solucionado esto nos aparece otro problema; necesitamos conocer la cantidad de dígitos que tiene nuestro número. Para obtener el número de dígitos usando solo propiedades matemáticas podemos tirar del logaritmo en base 10 (usando solo su parte entera):

digitos = int(log10(n)) + 1

Para entenderlo basta con recordar lo que es un logaritmo en base 10, que no es más que el exponente al cual hay que elevar 10 para obtener dicho número.

Si aplicamos lo anterior a código Python, lo primero que necesitaremos es calcular el logaritmo en base 10, para ello recurrimos al módulo math de la biblioteca estándar para poder usar la función log10().

Con esto nuestro código sería:

from math import log10

def digitos_iguales(num):
    return num % ((10**int(log10(num))+1) - 1) // 9) == 0

Esto funciona pero hay dos problemas:

  • Si introducimos un número negativo el intérprete nos lanza un error del tipo:

    ValueError: math domain error

    esto se debe a intentar calcular el logaritmo de un número negativo. Para solucionarlo usamos el valor absoluto para ese cálculo mediante la función preconstruida abs()

  • Solucionado lo anterior, si el entero que introducimos es 0 nos tira el mismo error (log(0)). Para solucionarlo basta con usar un or antes de la igualdad para descartar este caso de la siguiente forma:

    num == 0 or num % ((10**int(log10(abs(num))+1) - 1) // 9) == 0

Con esto hemos llegado a la función que puse al inicio.

Si tienes el número en una cadena basta hacer:

n = int(cadena)

para transformarlo a un entero (siempre que la cadena sea un entero válido, no un float o otra cosa).

P.D: gracias a Mariano por las observaciones sobre mi código inicial que han sido de mucha ayuda para mejorarlo. (ver comentarios).

FJSevilla
  • 55,603
  • 7
  • 35
  • 58
  • 7
    Tu respuesta es realmente excelente. Algunos detalles: **1.** Cuando el último dígito es `0`, ejemplo `110`, lleva a `n//0` (error). Esto se puede arreglar con prácticamente la misma propiedad que usaste: `333%111==0` **∀** n. **2.** Luego de arreglar eso, `digitos_iguales(0)` también daría error, y agregaría el caso especial para `0`. **3.** Enteros negativos :-) Se resuelve fácil con `abs()`. http://rextester.com/EBGE40597 – Mariano Nov 12 '16 at 12:33
  • Muchas gracias por las observaciones @Mariano. La 2ª y 3ª las conocía (por eso puse que la función era válida para enteros mayores de 0). No tenía mucho tiempo y decidí dejarla así para completarla después. No obstante la 1ª (si el último dígito es 0) se me pasó totalmente, uno de mis clásicos bugs tontos he de decir.... XD. Con tu permiso he modificado el código siguiendo tus recomendaciones (copiando más bien...XD). Originalmente está función es una modificacíon de algo que hice para contestar una pregunta de [Project Euler](https://projecteuler.net/). – FJSevilla Nov 12 '16 at 12:57
  • 2
    Mi comentario iba sólo a los detalles (obvio que era para que la uses). Lo importante ya estaba en tu respuesta: el `10^0+10^1+10^2+...+10^n` como múltiplo de estos números, y [la propiedad de ser `=(10^n-1)/9`](https://www.youtube.com/watch?v=Nw5gGn6DJdw).. Creo que es una respuesta canónica y sería espectacular si en algún otro momento/día seguís completando detalles en la descripción, para que quede como referencia a futuros lectores (ya tenía decidido iniciar una recompensa en la pregunta). – Mariano Nov 12 '16 at 13:13
15

Creo que te has explicado mal y por éso ha habido tanta confusión. De inicio tienes un número, no una "cadena", y quieres saber si todos los dígitos del número son el mismo dígito. Y quieres hacerlo por métodos numéricos, sin convertir el número a cadena ni a lista.

Una solución:

def digitos_iguales(n):
    m, c = divmod(n, 10)
    d = c

    while m>0 and d == c:
        m, d = divmod(m, 10)

    return (d==c)
ChemaCortes
  • 8,325
  • 18
  • 36
4

Esto debiera hacer el trabajo.

s = "1111"
if s.count(s[:1]) == len(s):
    print("todos iguales")

Edit

Ahora que re-leo la pregunta, me doy cuenta que no quieres analizar la cadena, sino el número, esto hará el trabajo:

s = "1111"
n = int(float(s))
ultimoDigito = n % 10
todosIguales = True
while (n != 0) & (todosIguales):
    digito = n % 10
    n = n // 10
    todosIguales = digito == ultimoDigito

if todosIguales:
    print("todos son iguales")
else:
    print("hay al menos un dígito diferente")
jachguate
  • 25,659
  • 7
  • 35
  • 61
  • Claro pero eso seria utilizando el numero como string o no? Ya que usando la longitud(len) "clasificas" al numero como palabra. – Facu Arg Nov 12 '16 at 00:55
3

Con una funcion recursiva equivalente a la de ChemaCortes

def todosiguales(n,d=False):
  if n<10:
    return True if not d else n==d
  else:
    m, r = divmod(n, 10)
    return (not d or r==d) and todosiguales(m, r)
Serg M Ten
  • 131
  • 3
2

Creo que esto sea a lo que te refieres. Para resolver eso sin usar listas, puedes tomar como base el primer caracter y a partir de ahi hacer la comparacion con los demas caracteres del string, por ejemplo:

def funcion(n):
    flag = False
    for i in range(0,len(n)):
        if n[0] != n[i]:
            print "este numero es diferente a los demas --> %s" %n[i]
            flag = True
    if flag:
        print "se encontraron diferencias..."
    else:
        print "todos los numeros son iguales..."
funcion("1111")

Espero haber ayudado con eso! Saludos! Happy conding ;)

Yasser Batas
  • 126
  • 1
  • 4
2

Aquí te dejo una solución, espero te sirva y ayude con lo que estés realizando.

def NumerosIguales(numero)
    numero = abs(numero)
    if numero < 9:
       return "Todos son iguales"
    ultimo = numero % 10
    while (numero != 0):
       digito = n % 10
       if digito != ultimo:
          return "Existe uno diferente"
       numero = numero  // 10
    return "Todos son iguales"
Randall Sandoval
  • 2,391
  • 1
  • 18
  • 36
2

Asi:

Matemáticamente puedes descomponer los dígitos de un numero dividiéndolo entre su base, como usamos un sistema decimal, es decir en base 10 entonces para ir navegando por sus dígitos simplemente lo vamos dividiendo entre 10.

Por Ejemplo: del numero 3423

3423 % 10 = 3

3423 // 10 = 342

342 % 10 = 2

342 // 10 = 34

34 % 10 = 4

34 // 10 = 3

3 % 10 = 3

3 // 10 = 0

la idea seria simplemente guardar el primer dígito desglosado en una variable y luego ir comparándolo con el resto de los digitos, si alguno falla "zas" no todos los digitos son iguales si no falla hasta terminar con todos los digitos "eureka" todos los digitos son iguales.

def digitos_iguales(n):
    n = abs(int(n))
    d = n % 10
    while n > 9:
        n = n // 10
        if d != n % 10:
            return False;
    return True

Ej:

>>> var = "999999"
>>> digitos_iguales(int(var))
True
>>> var = "2222220"
>>> digitos_iguales(int(var))
False
Neyer
  • 1,039
  • 1
  • 9
  • 16
1

Parecido a respuesta de ChemaCortes:

Actualizado (más simple y robusto ante overflows)

# Devuelve True si el numero tiene todos sus digitos iguales
#  n deberria ser un numero entero positivo
def todosiguales(n):
    dig = n % 10
    n = n // 10      
    while n > 0:
       if n % 10 != dig:
            return False
       n = n // 10      
    return True

# para testear    
def test_todosiguales(n):
   if todosiguales(n):   
      print("El numero " + str(n) + " tiene los digitos iguales \n")
   else:   
      print("El numero " + str(n) + " NO tiene los digitos iguales \n")

test_todosiguales(2323)
test_todosiguales(2222)
test_todosiguales(1)
test_todosiguales(0)
test_todosiguales(4)
test_todosiguales(41)
test_todosiguales(10)
test_todosiguales(200)
test_todosiguales(88888888888888888)
test_todosiguales(101)
test_todosiguales(121)
test_todosiguales(212)
test_todosiguales(111111)
leonbloy
  • 2,513
  • 7
  • 18
  • Sería bueno que los que votan para abajo se molestaran en comentar los motivos. Hace más de 7 años que aporto en SO y (entre esta y otras experiencias) ya estoy tentado a concluir que esta comunidad en particular no vale el esfuerzo. – leonbloy Dec 02 '16 at 12:48
0

Debido a que no usas bien el idioma castellano, no se entiende tu pregunta.

Como puedo saber que "1111" tiene todas sus cifras iguales sin poder utilizar listas, analizarlo como string, etc.

Esto se puede interpretar de dos formas.

  1. Saber que tiene sus cifras iguales, sin necesidad de usar listas, ni analizarlo como string.

  2. Sin usar listas, analizándolo como string.

A pesar de esto, puedo dar una respuesta "a ojo". Voy a suponer que es lo segundo.

No se puede, ya que los strings son cadenas de caracteres, es decir, un vector unidimensional, que es lo mismo que una lista.

El string "1111" es una lista, ['1', '1', '1', '1']... ¿Es posible saber si todos son iguales, sin recorrer la lista? No, esto no es posible, y esto significa que a nivel bit es necesario comparar cada elemento con su siguiente.

Si fuera un número decimal pasaría exactamente lo mismo, es necesario transformarlo como si fuera una lista de decimales.

-1

Entiendo que el análisis debe ser exclusivamente matemático

Aún así, aquí dejo una versión, usando Expresiones Regulares

#python 2.7.6

import re

def digitos_iguales(numero):
    cadena = str(abs(int(numero)))
    return re.match( r'^'+cadena[0]+'{'+str(len(cadena))+'}$', cadena) != None;

Resultados:

print digitos_iguales(-101) #False
print digitos_iguales(101) #False
print digitos_iguales(-111) #True
print digitos_iguales(111) #True
print digitos_iguales(0) #True

Demo

Marcos
  • 30,626
  • 6
  • 28
  • 63
-4

Mi grano de arena, pero en javaScript, así se ve el resultado:
Método simple comparando el dígito menor con el resto hasta que encuentra uno distinto o se queda sin dígitos a comparar.

for (var i=0; i<10000; i++)
 document.write (i,":",tieneTodosLosDigitosIguales(i),", ");

function tieneTodosLosDigitosIguales(numero){
 var digitosSonIguales=true; // 1 digito ( 0 incluido) = true
 var digitoAcomparar=digitoMenor(numero);
 var numeroRestante=Math.floor(numero/10);
 while(digitosSonIguales && numeroDigitos(numeroRestante)>0){
  digitosSonIguales = digitoAcomparar==digitoMenor(numeroRestante);
  numeroRestante = Math.floor(numeroRestante/10);
 }
 return digitosSonIguales;
}

function digitoMenor(numero){
 return numero%10;
}

function numeroDigitos(numero){
 var contadorDigitos=0; //0 = 0 digitos
 while (numero) {
  contadorDigitos++;
  numero=Math.floor(numero/10);
 }
 return contadorDigitos;
}
Arnau Castellví
  • 2,370
  • 8
  • 14