Aller au contenu

L'Établi des Maths Cours

Outils pour apprendre et pratiquer

Première · Algorithmique et Programmation · 1S3

Cours et exercices corrigés de première : Algorithmique et programmation en Python : listes, suites, seuils et simulations

Listes Python (création, compréhension, append, len, indices, parcours), calcul de termes et de sommes de suites, algorithmes de seuil avec while, simulation d'expériences aléatoires et méthode de balayage.

Objectifs du chapitre

Le cours

1. Les listes en Python

Une liste est une suite ordonnée de valeurs, écrite entre crochets : L = [5, 8, 13].

  • Les indices commencent à 00 : L[0] vaut 55, L[2] vaut 1313 ; L[-1] désigne le dernier élément.
  • len(L) est le nombre d'éléments ; les indices vont donc de 00 à len(L) - 1.
  • L.append(x) ajoute x à la fin ; L[i] = x remplace l'élément d'indice i.
  • Supprimer : L.pop() retire (et renvoie) le dernier élément ; del L[i] supprime l'élément d'indice i ; L.remove(x) supprime la première occurrence de la valeur x. Avec L = [5, 8, 13] : après L.remove(8), L vaut [5, 13] ; après del L[0], L vaut [13].
  • sum(L), max(L), min(L) donnent la somme, le maximum, le minimum.
L = []
for k in range(5):
    L.append(k ** 2)
print(L)        # affiche [0, 1, 4, 9, 16]
print(len(L))   # affiche 5

2. Listes en compréhension et parcours

On peut construire une liste en une ligne, en compréhension :

carres = [k ** 2 for k in range(5)]                # [0, 1, 4, 9, 16]
pairs = [k for k in range(1, 20) if k % 2 == 0]   # entiers pairs de 2 à 18

Deux façons de parcourir une liste :

for x in L:              # par élément
    print(x)
for i in range(len(L)):  # par indice
    print(i, L[i])

Le parcours par indice est utile quand on a besoin de la position (par exemple pour comparer L[i] et L[i + 1]).

3. Calculer les termes d'une suite

  • Suite explicite un=f(n)u_n = f(n) : on programme une fonction.
def u(n):
    return 3 * n ** 2 - 1
  • Suite récurrente u0=2u_0 = 2, un+1=3un−1u_{n+1} = 3u_n - 1 : on répète l'affectation nn fois ; après nn tours, la variable contient unu_n.
def terme(n):
    u = 2
    for k in range(n):
        u = 3 * u - 1
    return u

def premiers_termes(n):
    L = [2]
    for k in range(n):
        L.append(3 * L[k] - 1)
    return L          # [u0, u1, ..., un]

terme(3) vaut 4141 et premiers_termes(3) vaut [2, 5, 14, 41].

4. Sommes de termes

Pour calculer Sn=u0+u1+⋯+unS_n = u_0 + u_1 + \dots + u_n, on utilise un accumulateur s initialisé à 00 :

def somme(n):
    s = 0
    u = 1
    for k in range(n + 1):
        s = s + u        # on ajoute u_k
        u = 2 * u        # on calcule u_(k+1)
    return s

Ici uk=2ku_k = 2^k et somme(n) vaut 1+2+⋯+2n=2n+1−11 + 2 + \dots + 2^n = 2^{n+1} - 1. Attention à l'ordre des deux instructions de la boucle et au nombre de termes : de u0u_0 à unu_n, il y a n+1n + 1 termes.

5. Algorithme de seuil

Pour une suite croissante qui tend vers +∞+\infty, on cherche le plus petit rang nn tel que un≥Au_n \ge A. On répète le calcul tant que le seuil n'est pas atteint :

def seuil(A):
    n = 0
    u = 500
    while u < A:
        u = 1.04 * u
        n = n + 1
    return n

À la sortie de la boucle, u vaut unu_n et c'est le premier terme supérieur ou égal à AA. Pour une suite décroissante, la condition devient while u > A:. (Voir aussi le chapitre 1A5.)

6. Simulation et fréquences

Le module random permet de simuler le hasard :

  • random() renvoie un flottant aléatoire de [0;1[[0 ; 1[ ; la condition random() < p est vraie avec la probabilité pp ;
  • randint(a, b) renvoie un entier aléatoire entre aa et bb inclus.
from random import randint

def frequence_sept(N):
    c = 0
    for i in range(N):
        if randint(1, 6) + randint(1, 6) == 7:
            c = c + 1
    return c / N

Pour NN grand, la fréquence obtenue est proche de la probabilité 636=16\frac{6}{36} = \frac{1}{6}, et la moyenne de valeurs simulées est proche de l'espérance (loi des grands nombres, voir 1S2).

7. Exemples classiques : factorielle, Fibonacci, Syracuse

def factorielle(n):
    p = 1
    for k in range(1, n + 1):
        p = p * k
    return p

def fibonacci(n):        # n premiers termes (n >= 2) : 1, 1, 2, 3, 5...
    L = [1, 1]
    while len(L) < n:
        L.append(L[-1] + L[-2])
    return L

def syracuse(a):         # termes à partir de a, jusqu'à atteindre 1
    L = [a]
    while a != 1:
        if a % 2 == 0:
            a = a // 2
        else:
            a = 3 * a + 1
        L.append(a)
    return L
  • factorielle(5) vaut 5!=1×2×3×4×5=1205! = 1 \times 2 \times 3 \times 4 \times 5 = 120.
  • fibonacci(8) vaut [1, 1, 2, 3, 5, 8, 13, 21] : chaque terme est la somme des deux précédents.
  • syracuse(7) contient 1717 termes (de 77 à 11) et atteint au maximum 5252. Personne ne sait démontrer que la suite atteint 11 quel que soit l'entier de départ : c'est la conjecture de Syracuse.

8. Fréquences d'apparition des lettres d'un texte

def frequences(texte):
    alphabet = "abcdefghijklmnopqrstuvwxyz"
    lettres = [c for c in texte.lower() if c in alphabet]
    return [(l, lettres.count(l) / len(lettres)) for l in alphabet]

La fonction renvoie une liste de couples (lettre, fréquence). Sur un long texte en français, le « e » est nettement la lettre la plus fréquente ; la répartition est différente en anglais. Ces fréquences servent par exemple à décrypter un message codé par décalage des lettres.

9. Programmation modulaire

On découpe un problème en fonctions simples, que l'on combine. Par exemple, pour calculer u0+u1+⋯+unu_0 + u_1 + \dots + u_n avec uk=2ku_k = 2^k, on sépare le calcul d'un terme et celui de la somme :

def u(k):
    return 2 ** k

def somme(n):
    s = 0
    for k in range(n + 1):
        s = s + u(k)
    return s

somme(10) vaut 211−1=2 0472^{11} - 1 = 2\,047. Pour une autre suite, il suffit de modifier la fonction u : la fonction somme reste inchangée.

Méthodes et exemples rédigés

Méthode : Prévoir le contenu d'une liste

Exemple

Que contient la liste L après l'exécution de L = [2 * k + 1 for k in range(3, 8)] ? Que vaut L[2] ?

  1. Étape 1 (Valeurs de k) : range(3, 8) donne k=3,4,5,6,7k = 3, 4, 5, 6, 7 (55 valeurs, la borne 88 est exclue).

  2. Étape 2 (Éléments) : on calcule 2k+12k + 1 : L = [7, 9, 11, 13, 15].

  3. Étape 3 (Indice) : les indices commencent à 00, donc L[2] est le troisième élément : 1111 (obtenu pour k=5k = 5, et non pour k=2k = 2).

  4. Conclusion : L = [7, 9, 11, 13, 15], len(L) vaut 55 et L[2] vaut 1111.

Méthode : Programmer un algorithme de seuil

Exemple

Une population de 2 0002\,000 individus diminue de 5 %5\,\% par an. Déterminer avec un programme au bout de combien d'années elle devient inférieure ou égale à 1 0001\,000.

  1. Étape 1 (Modélisation) : u0=2000u_0 = 2000 et un+1=0,95unu_{n+1} = 0{,}95u_n (coefficient multiplicateur 1−0,051 - 0{,}05).

  2. Étape 2 (Condition de la boucle) : on continue tant que un>1000u_n > 1000.

  3. Étape 3 (Programme) :

    u = 2000
    n = 0
    while u > 1000:
        u = 0.95 * u
        n = n + 1
    print(n)
    
  4. Conclusion : u13=2000×0,9513≈1027>1000u_{13} = 2000 \times 0{,}95^{13} \approx 1027 > 1000 et u14≈976≤1000u_{14} \approx 976 \le 1000 : le programme affiche 1414 ans.

Méthode : Calculer une somme de termes

Exemple

Écrire un programme qui calcule S=3+7+11+⋯+79S = 3 + 7 + 11 + \dots + 79.

  1. Étape 1 (Suite) : les termes forment une suite arithmétique de premier terme 33 et de raison 44 : uk=3+4ku_k = 3 + 4k.

  2. Étape 2 (Nombre de termes) : 3+4k=79  ⟺  k=193 + 4k = 79 \iff k = 19 ; il y a donc 2020 termes (kk de 00 à 1919).

  3. Étape 3 (Programme) :

    s = 0
    for k in range(20):
        s = s + 3 + 4 * k
    print(s)
    
  4. Conclusion : le programme affiche 820820, ce que confirme la formule 20×3+792=82020 \times \frac{3 + 79}{2} = 820.

Méthode : Approcher une solution par balayage

Exemple

Encadrer 7\sqrt{7} entre deux multiples consécutifs de 0,250{,}25.

  1. Étape 1 (Principe) : on part de x=0x = 0 et on augmente xx d'un pas 0,250{,}25 tant que x2<7x^2 < 7.

  2. Étape 2 (Programme) :

    x = 0
    while x * x < 7:
        x = x + 0.25
    print(x - 0.25, x)
    
  3. Étape 3 (Exécution) : 2,52=6,25<72{,}5^2 = 6{,}25 < 7 et 2,752=7,5625≥72{,}75^2 = 7{,}5625 \ge 7 : la boucle s'arrête pour x=2,75x = 2{,}75.

  4. Conclusion : le programme affiche 2.5 2.75, donc 2,5<7≤2,752{,}5 < \sqrt{7} \le 2{,}75. Un pas plus petit donne un encadrement plus précis.

Pièges fréquents

Questions de révision

Essaie de répondre de tête avant d'afficher la réponse.

Que vaut [k * k for k in range(1, 5)] ?

[1, 4, 9, 16].

Si L = [4, 7, 1, 9], que valent L[1], L[-1] et len(L) ?

77, 99 et 44.

Comment ajouter la valeur x à la fin de la liste L ?

Avec l'instruction L.append(x).

Quelle boucle utilise-t-on pour un algorithme de seuil, et pourquoi ?

Une boucle while, car on ne connaît pas à l'avance le nombre de répétitions.

Que renvoie randint(1, 6) ?

Un entier aléatoire entre 11 et 66, bornes incluses (simulation d'un dé équilibré).

Pour NN grand, de quoi la moyenne de NN gains simulés est-elle proche ?

De l'espérance du gain (loi des grands nombres).

Que renvoie factorielle(4) ?

4!=1×2×3×4=244! = 1 \times 2 \times 3 \times 4 = 24.

Exercices corrigés

Exercice 1 Liste en compréhension

Palier 1 · découverte

Qu'affiche le programme Python suivant ?

L = [3 * k for k in range(1, 5)]
print(L)
  1. « [3, 6, 9, 12] »
  2. « [0, 3, 6, 9, 12] »
  3. « [3, 6, 9, 12, 15] »
  4. « [0, 3, 6, 9] »
Un indice

range(1, 5) parcourt les entiers 11, 22, 33 et 44.

Voir la correction

Bonne réponse : A. « [3, 6, 9, 12] »

Pour k=1,2,3,4k = 1, 2, 3, 4 (la borne 55 est exclue), on calcule 3k3k : la liste est [3, 6, 9, 12].

Exercice 2 Terme d'une suite récurrente

Palier 2 · application

On considère la suite définie par u0=1u_0 = 1 et un+1=2un+3u_{n+1} = 2u_n + 3. Qu'affiche le programme suivant ?

u = 1
for k in range(4):
    u = 2 * u + 3
print(u)
  1. 6161
  2. 2929
  3. 125125
  4. 1313
Un indice

La boucle s'exécute 44 fois : à la fin, u contient u4u_4.

Voir la correction

Bonne réponse : A. 6161

u1=2×1+3=5u_1 = 2 \times 1 + 3 = 5, u2=13u_2 = 13, u3=29u_3 = 29, u4=61u_4 = 61. Le programme affiche 6161.

Exercice 3 Algorithme de seuil

Palier 3 · approfondissement

Qu'affiche le programme Python suivant ?

u = 3
n = 0
while u < 1000:
    u = 2 * u
    n = n + 1
print(n)
  1. 99
  2. 88
  3. 1010
  4. 15361536
Un indice

Après nn tours, u vaut 3×2n3 \times 2^n.

Voir la correction

Bonne réponse : A. 99

3×28=768<10003 \times 2^8 = 768 < 1000 et 3×29=1536≥10003 \times 2^9 = 1536 \ge 1000. La boucle s'arrête après 99 tours : le programme affiche 99.

Exercice 4 Simulation de deux dés

Palier 4 · défi

On exécute le programme suivant.

from random import randint

def frequence(N):
    c = 0
    for i in range(N):
        a = randint(1, 6)
        b = randint(1, 6)
        if a + b >= 10:
            c = c + 1
    return c / N

print(frequence(100000))

Autour de quelle valeur la valeur affichée fluctue-t-elle ?

  1. 16\frac{1}{6}
  2. 112\frac{1}{12}
  3. 14\frac{1}{4}
  4. 311\frac{3}{11}
Un indice

Pour NN grand, la fréquence est proche de la probabilité de l'événement « a+b≥10a + b \ge 10 ».

Voir la correction

Bonne réponse : A. 16\frac{1}{6}

Somme 1010 : 33 couples, somme 1111 : 22 couples, somme 1212 : 11 couple, soit 66 couples favorables sur 3636. La probabilité vaut 636=16\frac{6}{36} = \frac{1}{6} : d'après la loi des grands nombres, la fréquence affichée fluctue autour de 16\frac{1}{6}.