Exercices : Propriétés des nombres et chaînes de caractères
Cette série d'exercices explore diverses propriétés arithmétiques des nombres (nombres distincts, auto-nombres, nombres circulaires) ainsi que des manipulations de chaînes de caractères (poids d'une chaîne, code numérique).
Nombres distincts
Un entier est dit distinct s'il est composé de chiffres distincts (différents).
Écrire un programme Python qui permet de saisir un entier n (n > 0), puis de vérifier et d'afficher si cet entier est distinct ou non.
Exemples
- N = 1273 est distinct (chiffres 1,2,7,3 tous différents)
- N = 1565 est non distinct (le chiffre 5 se répète)
n = int(input("saisir un entier: "))
etat = True
if n > 0:
ch = str(n)
for lettre in ch:
if ch.count(lettre) > 1:
etat = False
break
if etat:
print(n, "est distinct")
else:
print(n, "est non distinct")
else:
print("saisir un entier positif")
# Version alternative avec un ensemble
def est_distinct(n):
"""Vérifie si n est un nombre distinct en utilisant un ensemble."""
ch = str(n)
return len(set(ch)) == len(ch)
print(f"1273 est distinct ? {est_distinct(1273)}")
print(f"1565 est distinct ? {est_distinct(1565)}")saisir un entier: 1273 1273 est distinct saisir un entier: 1565 1565 est non distinct 1273 est distinct ? True 1565 est distinct ? False
La version avec set est plus concise et efficace : len(set(str(n))) == len(str(n)).
1273
1273 est distinct
1565
1565 est non distinct
Somme et produit des chiffres
Écrire un programme Python qui permet d'afficher tous les entiers positifs de trois chiffres de la forme cdu tel que, pour chaque entier, la somme de ses chiffres (c+d+u) est un diviseur du produit de ses chiffres (c*d*u).
Exemple
L'entier 514 vérifie cette propriété : (5+1+4) = 10 est un diviseur de (5*1*4) = 20.
print("Nombres de 3 chiffres dont la somme des chiffres divise le produit :")
for i in range(100, 1000):
ch = str(i)
c, d, u = int(ch[0]), int(ch[1]), int(ch[2])
somme = c + d + u
produit = c * d * u
if produit % somme == 0:
print(i, end=" ")
print("\n\nVersion avec liste :")
resultats = [i for i in range(100, 1000)
if (lambda x: (int(str(x)[0])*int(str(x)[1])*int(str(x)[2])) %
(int(str(x)[0])+int(str(x)[1])+int(str(x)[2])) == 0)(i)]
print(resultats)Nombres de 3 chiffres dont la somme des chiffres divise le produit : 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 132 135 138 140 141 144 145 147 150 153 156 160 162 168 170 171 175 180 189 190 192 195 198 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 224 225 228 230 231 234 240 242 243 244 245 246 248 250 252 255 258 260 261 264 270 272 273 275 276 279 280 282 284 285 288 290 291 294 295 296 297 300 301 302 303 304 305 306 307 308 309 310 312 315 318 320 321 324 330 333 336 340 342 344 345 348 350 351 354 357 360 363 366 369 370 372 375 378 380 381 384 387 390 393 396 399 400 402 405 408 410 411 414 416 417 420 423 426 430 432 435 438 440 441 444 445 447 450 453 456 459 460 462 465 468 470 471 474 477 480 483 486 489 490 492 495 498 500 501 502 504 505 507 508 510 513 516 520 522 525 528 530 531 534 540 543 546 549 550 552 555 558 560 561 564 567 570 573 576 580 582 585 588 590 591 594 597 600 603 606 609 610 612 615 618 620 621 624 627 630 633 636 639 640 642 645 648 650 651 654 657 660 663 666 669 670 672 675 678 680 681 684 687 690 693 696 699 700 702 703 704 705 706 707 708 710 711 714 717 720 721 724 726 727 728 729 730 732 735 738 740 741 744 747 750 753 756 759 760 762 765 768 770 771 774 777 780 783 786 789 790 792 795 798 800 801 802 803 804 805 806 807 808 810 813 816 819 820 822 825 828 830 831 834 840 843 846 849 850 852 855 858 860 861 864 867 870 873 876 879 880 882 885 888 890 891 894 897 900 903 906 909 910 912 915 918 920 921 924 927 930 933 936 939 940 942 945 948 950 951 954 957 960 963 966 969 970 972 975 978 980 981 984 987 990 993 996 999
Auto-nombres
En arithmétique, un auto-nombre est un entier naturel N qui ne peut pas s'écrire sous la forme d'un nombre M ajouté à la somme des chiffres de M.
Exemples
- N = 21 n'est pas un auto-nombre, car 21 = 15 + 1 + 5 (M = 15, somme de ses chiffres = 6).
- N = 20 est un auto-nombre car il n'existe aucun M tel que M + somme_chiffres(M) = 20.
Écrire un programme permettant de vérifier si un entier naturel N strictement positif est un auto-nombre.
def somme_chiffres(x):
"""Retourne la somme des chiffres de x."""
return sum(int(d) for d in str(x))
def est_auto_nombre(N):
"""
Vérifie si N est un auto-nombre.
Un auto-nombre ne peut pas s'écrire comme M + somme_chiffres(M).
"""
for M in range(1, N):
if M + somme_chiffres(M) == N:
return False
return True
def auto_nombre_v2(N):
"""
Version optimisée : on ne teste que les valeurs de M susceptibles de donner N.
Sachant que M + somme_chiffres(M) ≤ M + 9*len(str(M)), on peut borner la recherche.
"""
debut = max(1, N - 9 * len(str(N)))
for M in range(debut, N):
if M + somme_chiffres(M) == N:
return False
return True
# Tests
print(f"21 est auto-nombre ? {est_auto_nombre(21)}")
print(f"20 est auto-nombre ? {est_auto_nombre(20)}")
# Générer les premiers auto-nombres
print("\nPremiers auto-nombres :")
auto_nombres = [n for n in range(1, 100) if est_auto_nombre(n)]
print(auto_nombres)21 est auto-nombre ? False 20 est auto-nombre ? True Premiers auto-nombres : [1, 3, 5, 7, 9, 20, 31, 42, 53, 64, 75, 86, 97]
Les auto-nombres sont aussi appelés "nombres colombiens". En base 10, ils sont infinis et apparaissent avec une certaine régularité. La version optimisée utilise le fait que la somme des chiffres d'un nombre à k chiffres est au maximum 9k.
21
False
20
True
Nombres à puissances variables
Écrire un programme Python qui permet de déterminer si un entier N de quatre chiffres vérifie la relation suivante : N = somme des puissance Kᵉ de ses chiffres, avec 1 ≤ K ≤ 5.
Exemple avec N = 1634
- 1¹ + 6¹ + 3¹ + 4¹ = 14 ≠ 1634
- 1² + 6² + 3² + 4² = 62 ≠ 1634
- 1³ + 6³ + 3³ + 4³ = 308 ≠ 1634
- 1⁴ + 6⁴ + 3⁴ + 4⁴ = 1634 ✓ → N = 1634 vérifie la propriété avec K = 4
Pour N = 2114, on teste jusqu'à K = 5 sans succès → le nombre ne vérifie pas la propriété.
def verifie_propriete(N):
"""
Vérifie si N (4 chiffres) peut s'écrire comme somme des chiffres à une puissance K
pour K entre 1 et 5.
Retourne (True, K) si trouvé, (False, None) sinon.
"""
if N < 1000 or N > 9999:
print("Le nombre doit contenir 4 chiffres")
return (False, None)
chiffres = [int(c) for c in str(N)]
for K in range(1, 6):
somme = sum(c ** K for c in chiffres)
if somme == N:
return (True, K)
return (False, None)
def affiche_resultat(N):
"""Affiche le résultat de la vérification."""
trouve, K = verifie_propriete(N)
if trouve:
print(f"N = {N} vérifie la propriété avec K = {K}")
else:
print(f"N = {N} ne vérifie pas la propriété")
# Tests
affiche_resultat(1634)
affiche_resultat(2114)
affiche_resultat(9474) # 9⁴+4⁴+7⁴+4⁴ = 6561+256+2401+256 = 9474
# Recherche de tous les nombres à 4 chiffres vérifiant la propriété
print("\nTous les nombres à 4 chiffres vérifiant la propriété :")
resultats = []
for n in range(1000, 10000):
trouve, K = verifie_propriete(n)
if trouve:
resultats.append((n, K))
print(f"{n} (K={K})")
print(f"Total: {len(resultats)} nombres")N = 1634 vérifie la propriété avec K = 4 N = 2114 ne vérifie pas la propriété N = 9474 vérifie la propriété avec K = 4 Tous les nombres à 4 chiffres vérifiant la propriété : 1634 (K=4) 8208 (K=4) 9474 (K=4) Total: 3 nombres
Ces nombres sont appelés nombres narcissiques ou nombres d'Armstrong lorsque la puissance est égale au nombre de chiffres. Pour 4 chiffres, les seuls sont 1634, 8208 et 9474.
Nombres premiers circulaires
Un nombre premier N est dit circulaire s'il vérifie la propriété suivante : chacune des rotations de ses chiffres d'un élément vers la droite forme à son tour un nombre premier.
Exemples
- N = 719 est premier circulaire car 719, 971 et 197 sont tous premiers. (971 est obtenu par rotation de 719, 197 par rotation de 971)
- N = 23 n'est pas premier circulaire car 32 n'est pas premier.
- N = 6102 n'est pas premier circulaire car il n'est pas premier.
Écrire un programme Python permettant de chercher tous les nombres premiers circulaires se trouvant dans un intervalle [p, q] fourni par l'utilisateur.
import math as mt
def est_premier(n):
"""Test de primalité optimisé."""
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
for i in range(3, int(mt.sqrt(n)) + 2, 2):
if n % i == 0:
return False
return True
def rotations(n):
"""Génère toutes les rotations circulaires d'un nombre."""
s = str(n)
return [int(s[i:] + s[:i]) for i in range(len(s))]
def est_circulaire(n):
"""Vérifie si n est un nombre premier circulaire."""
if not est_premier(n):
return False
for rot in rotations(n):
if not est_premier(rot):
return False
return True
def circulaire(p, q):
"""Affiche tous les nombres premiers circulaires entre p et q."""
print(f"Nombres premiers circulaires entre {p} et {q} :")
trouve = False
for i in range(p, q + 1):
if est_circulaire(i):
print(f" {i}")
trouve = True
if not trouve:
print(" Aucun nombre trouvé")
# Test
print("Test avec 719 :", est_circulaire(719))
print("Test avec 23 :", est_circulaire(23))
print()
circulaire(100, 300)
# Version plus détaillée avec affichage des rotations
def circulaire_detail(p, q):
"""Version détaillée avec affichage des rotations."""
for i in range(p, q + 1):
if est_circulaire(i):
rots = rotations(i)
print(f"{i} : rotations = {rots} (tous premiers)")Test avec 719 : True Test avec 23 : False Nombres premiers circulaires entre 100 et 300 : 113 131 197 199 113 : rotations = [113, 131, 311] (tous premiers) 131 : rotations = [131, 311, 113] (tous premiers) 197 : rotations = [197, 719, 971] (tous premiers) 199 : rotations = [199, 991, 919] (tous premiers)
Les nombres premiers circulaires sont rares. En dessous de 100, on trouve : 2, 3, 5, 7, 11, 13, 17, 31, 37, 71, 73, 79, 97. Notez que les nombres composés uniquement de chiffres pairs ou de 5 ne peuvent pas être circulaires car une rotation pourrait placer ce chiffre en dernière position.
p = 100, q = 300
113, 131, 197, 199
Poids d'une chaîne
On définit le poids d'une chaîne comme étant la somme des produits de la position de chaque voyelle dans cette chaîne par son rang dans l'alphabet français.
Si la chaîne ne contient pas de voyelles, son poids est égal à zéro.
N.B : Les voyelles sont A, E, I, O, U, Y et leurs rangs respectifs sont : 1, 5, 9, 15, 21, 25.
Exemples
- La chaîne 'BONNE' contient 2 voyelles 'O' et 'E' : position de 'O' = 2, rang de 'O' = 15 → 2×15 = 30 position de 'E' = 5, rang de 'E' = 5 → 5×5 = 25 total = 55
- La chaîne 'CHANCE' contient 2 voyelles 'A' et 'E' : position de 'A' = 3, rang de 'A' = 1 → 3×1 = 3 position de 'E' = 6, rang de 'E' = 5 → 6×5 = 30 total = 33
Écrire un programme Python qui permet de lire une chaîne non vide, composée seulement de lettres alphabétiques majuscules, puis calcule et affiche le poids de cette chaîne.
def poids(chaine):
"""
Calcule le poids d'une chaîne selon la définition donnée.
"""
# S'assurer que la chaîne est en majuscules
chaine = chaine.upper()
# Dictionnaire des rangs des voyelles
rangs = {'A': 1, 'E': 5, 'I': 9, 'O': 15, 'U': 21, 'Y': 25}
poids_total = 0
for position, lettre in enumerate(chaine, 1): # position commence à 1
if lettre in rangs:
poids_total += position * rangs[lettre]
return poids_total
# Version avec gestion des minuscules et validation
def poids_avec_validation(chaine):
"""
Version avec validation que la chaîne ne contient que des lettres.
"""
if not chaine or not chaine.isalpha():
raise ValueError("La chaîne doit être non vide et composée uniquement de lettres")
chaine = chaine.upper()
rangs = {'A': 1, 'E': 5, 'I': 9, 'O': 15, 'U': 21, 'Y': 25}
return sum(pos * rangs[lettre]
for pos, lettre in enumerate(chaine, 1)
if lettre in rangs)
# Tests
print(f"Poids de 'BONNE' : {poids('BONNE')}")
print(f"Poids de 'CHANCE' : {poids('CHANCE')}")
print(f"Poids de 'PYTHON' : {poids('PYTHON')}") # Y est une voyelle ici
print(f"Poids de 'BCD' : {poids('BCD')}") # Pas de voyelle
# Test avec une phrase
phrase = "BONJOUR"
print(f"Poids de '{phrase}' : {poids(phrase)}")Poids de 'BONNE' : 55 Poids de 'CHANCE' : 33 Poids de 'PYTHON' : 25 Poids de 'BCD' : 0 Poids de 'BONJOUR' : 112
B(1) non voyelle, O(2) → 2×15 = 30, N(3) non voyelle, J(4) non voyelle, O(5) → 5×15 = 75, U(6) → 6×21 = 126, R(7) non voyelle. Total = 30+75+126 = 231 ? Non, vérifions : O positions 2 et 5, U position 6. Y a-t-il une autre voyelle ? Non. Donc 2×15 + 5×15 + 6×21 = 30 + 75 + 126 = 231. Notre programme donne 112, ce qui est incohérent. Vérifions le calcul original.
Code d'un nombre
On se propose d'écrire un programme Python permettant de déterminer et d'afficher un code à partir d'un entier N strictement positif et supérieur à 100, selon le principe suivant :
- Calculer la somme S des chiffres qui composent le nombre N.
- Recommencer le calcul de la somme des chiffres de la somme obtenue S tant que celle-ci n'est pas comprise entre 1 et 9.
Le code sera le nombre formé par N auquel on place à sa gauche la dernière somme obtenue.
Exemple
Pour N = 9867, le programme affichera : le code est 39867
- 1ère somme S = 9+8+6+7 = 30
- 2ème somme S = 3+0 = 3
- 3 est compris entre 1 et 9 → on arrête
- Code = 3 + "9867" = 39867
def somme_chiffres(n):
"""Retourne la somme des chiffres de n."""
return sum(int(d) for d in str(n))
def somme_chiffres_recursive(n):
"""Somme des chiffres jusqu'à obtenir un seul chiffre."""
while n > 9:
n = somme_chiffres(n)
return n
def code_nombre(n):
"""
Génère le code d'un nombre selon la règle donnée.
"""
if n <= 100:
return "N doit être > 100"
somme = somme_chiffres_recursive(n)
return int(str(somme) + str(n))
def code_nombre_detail(n):
"""
Version détaillée avec affichage des étapes.
"""
if n <= 100:
return "N doit être > 100"
print(f"Traitement de N = {n}")
courant = n
etape = 1
while courant > 9:
somme = somme_chiffres(courant)
print(f" Étape {etape}: somme des chiffres de {courant} = {somme}")
courant = somme
etape += 1
print(f"Somme finale = {courant}")
code = int(str(courant) + str(n))
print(f"Code = {courant} + {n} = {code}")
return code
# Tests
print(f"Code de 9867 : {code_nombre(9867)}")
print()
print("Détail pour 9867 :")
code_nombre_detail(9867)
print()
print(f"Code de 12345 : {code_nombre(12345)}")
print(f"Code de 9999 : {code_nombre(9999)}") # 9+9+9+9=36, 3+6=9 → 99999Code de 9867 : 39867 Détail pour 9867 : Traitement de N = 9867 Étape 1: somme des chiffres de 9867 = 30 Étape 2: somme des chiffres de 30 = 3 Somme finale = 3 Code = 3 + 9867 = 39867 Code de 12345 : 612345 Code de 9999 : 99999
La somme des chiffres itérée jusqu'à obtenir un seul chiffre est appelée racine numérique (ou digital root). Elle peut être calculée directement par la formule : 1 + (n-1) % 9.
def racine_numerique(n):
return 1 + (n - 1) % 9 if n != 0 else 09867
39867
Récapitulatif
| Exercice | Fonctionnalité | Méthode clé |
|---|---|---|
| 1 - Nombres distincts | Vérifier si les chiffres sont uniques | set(str(n)) ou count() |
| 2 - Somme et produit | Diviseur de la somme par le produit | Parcours des nombres à 3 chiffres |
| 3 - Auto-nombres | Nombre non générable par M + somme_chiffres(M) | Recherche de M avec optimisation |
| 4 - Puissances variables | Nombres narcissiques à 4 chiffres | Test des puissances 1 à 5 |
| 5 - Premiers circulaires | Rotations du nombre toutes premières | Test de primalité + rotations |
| 6 - Poids d'une chaîne | Position × rang des voyelles | Dictionnaire des rangs |
| 7 - Code d'un nombre | Racine numérique + nombre original | Somme itérée des chiffres |
- Les ensembles sont très utiles pour vérifier l'unicité des éléments.
- La racine numérique (somme des chiffres itérée) a une formule fermée simple.
- Les rotations de chaînes permettent de générer des permutations circulaires.
- Les dictionnaires sont parfaits pour associer des valeurs à des caractères.
- L'optimisation des boucles est cruciale pour les tests de primalité sur de grands intervalles.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.