Exercices#
Algorithmique : le parcours séquentiel
Mode d’emploi
-
Niveau : ★ échauffement, ★★ classique (niveau bac), ★★★ défi ; les coups de pouce et les corrigés se déplient sous chaque exercice.
-
▶ À programmer et tester en Python. Le symbole
>>>figure une saisie dans la console. -
Sauf mention contraire, on n’utilise pas les fonctions toutes faites
sum,max,min: le but est d’écrire le parcours soi-même. -
Réflexe coût : pour chaque fonction, se demander combien de fois on parcourt le tableau.
-
Usage de l’IA, indiqué sur chaque exercice : aucune ; en appui (déboguer, reformuler, vérifier ; la réponse finale est écrite et comprise par vous) ; l’exercice s’appuie sur une réponse d’IA. Voir la charte d’usage de l’IA.
Le patron du parcours#
★ Exercice 1 — Lecture de trace #
• essentiel
Sans machine, dire ce que renvoie mystere([4, 1, 7, 2]).
def mystere(t):
r = 0
for x in t:
if x > r:
r = x
return r
Que calcule cette fonction en général ? Renvoie-t-elle un résultat correct si tous les éléments sont négatifs ? Expliquer.
Coup de pouce
Faire un tableau de trace : une ligne par tour, avec x et r. Refaire ensuite la trace avec [-3, -7] : la condition x > r est-elle vraie une seule fois ?
Corrigé
Remarque
On donne une version simple ; d’autres écritures sont possibles.
mystere([4, 1, 7, 2]) renvoie 7. La fonction calcule le maximum du tableau… mais seulement s’il est positif : le champion initial est 0. Sur un tableau tout négatif, comme [-3, -7], elle renvoie 0, qui n’est pas un élément du tableau : résultat faux. Il fallait initialiser avec t[0].
★ Exercice 2 — Reconnaître le patron #
▶ En suivant le patron du cours (initialisation, mise à jour, renvoi), écrire :
-
produit(t): le produit de tous les éléments ; -
concatener(mots): la chaîne obtenue en collant tous les mots d’un tableau de chaînes.
Coup de pouce
Seules l’initialisation et la mise à jour changent. Par quelle valeur commencer pour qu’elle ne modifie pas le résultat : pour un produit ? pour une chaîne que l’on allonge ?
Corrigé
Même patron que la somme ; on change l’initialisation (l’élément neutre : 1 pour un produit, la chaîne vide pour une concaténation) et la mise à jour.
def produit(t):
p = 1 # element neutre de la multiplication
for x in t:
p = p * x
return p
def concatener(mots):
resultat = "" # element neutre de la concatenation
for mot in mots:
resultat = resultat + mot
return resultat
Décliner : comptages, moyennes#
★ Exercice 3 — Compter dans un intervalle : code à trous #
• essentiel
La fonction nb_entre(t, a, b) doit renvoyer le nombre d’éléments du tableau t compris entre a et b (bornes incluses). Recopier et compléter les pointillés en suivant le patron du parcours (initialisation, mise à jour, renvoi).
def nb_entre(t, a, b):
c = ......
for x in ......:
if ...... and ......:
c = ......
return ......
>>> nb_entre([12, 5, 18, 9, 15], 10, 15)
2
Coup de pouce
C’est un compteur : quelle valeur avant la boucle, et de combien augmente-t-il ? « Compris entre a et b » se traduit par deux comparaisons qui doivent être vraies toutes les deux.
Corrigé
def nb_entre(t, a, b):
c = 0 # compteur : element neutre 0
for x in t:
if x >= a and x <= b: # mise a jour conditionnelle
c = c + 1
return c
nb_entre([12, 5, 18, 9, 15], 10, 15) renvoie bien 2 (les éléments 12 et 15). Les deux conditions sont reliées par and : il faut à la fois x >= a et x <= b.
▷ Erreur fréquente. relier les deux conditions par or : tout nombre est supérieur à a ou inférieur à b, et la fonction compte alors tous les éléments.
★★ Exercice 4 — Taux de réussite et moyenne pondérée #
• essentiel
▶ Les notes d’un élève sont rangées dans un tableau notes non vide ; le tableau coefs, de même longueur, donne leurs coefficients (coefs[i] est le coefficient de notes[i]). Écrire :
-
taux_reussite(notes): le pourcentage de notes supérieures ou égales à10; -
moyenne_ponderee(notes, coefs): la somme des produitsnotes[i] * coefs[i], divisée par la somme des coefficients.
>>> taux_reussite([12, 8, 15, 9])
50.0
>>> moyenne_ponderee([12, 8, 15], [2, 1, 1])
11.75
Coup de pouce
Question 1 : un compteur, puis une division par le nombre de notes. Question 2 : deux accumulateurs mis à jour dans la même boucle ; il faut lire à la fois notes[i] et coefs[i], donc parcourir par indice.
Coup de pouce 2 (début de solution)
def moyenne_ponderee(notes, coefs):
total = 0
total_coefs = 0
for i in range(len(notes)):
Corrigé
def taux_reussite(notes):
c = 0
for note in notes:
if note >= 10:
c = c + 1
return 100 * c / len(notes)
def moyenne_ponderee(notes, coefs):
total = 0 # somme des notes[i] * coefs[i]
total_coefs = 0 # somme des coefficients
for i in range(len(notes)):
total = total + notes[i] * coefs[i]
total_coefs = total_coefs + coefs[i]
return total / total_coefs
Pour moyenne_ponderee, on parcourt par indice : le même i donne la note et son coefficient. Les deux accumulateurs sont mis à jour dans la même boucle : un seul parcours. Sur l’exemple : \((12 \times 2 + 8 + 15) / (2 + 1 + 1) = 47 / 4 = 11{,}75\).
▷ Erreur fréquente. diviser par len(notes) au lieu de la somme des coefficients : on obtiendrait \(47 / 3\), qui n’est pas la moyenne pondérée.
Recherche séquentielle#
★ Exercice 5 — Un multiple dans le tableau #
• essentiel
▶ Écrire a_un_multiple(t, k) qui renvoie True si au moins un élément de t est un multiple de k, False sinon. La fonction doit s’arrêter dès qu’un multiple est trouvé. Combien de tours de boucle effectue a_un_multiple([7, 10, 3, 20], 5) ? Et a_un_multiple([7, 10, 3, 20], 6) ?
Coup de pouce
x est un multiple de k quand x % k == 0. Où placer return False : dans la boucle ou après ?
Corrigé
def a_un_multiple(t, k):
for x in t:
if x % k == 0:
return True # on s'arrete des qu'on trouve
return False # parcours fini sans succes
a_un_multiple([7, 10, 3, 20], 5) fait 2 tours : 10 est trouvé au deuxième tour, et return arrête aussitôt la fonction. a_un_multiple([7, 10, 3, 20], 6) fait 4 tours : aucun multiple de 6, il faut tout parcourir avant de répondre False. C’est le pire cas.
▷ Erreur fréquente. écrire else: return False dans la boucle : la fonction répond dès le premier élément, et a_un_multiple([7, 10, 3, 20], 5) renverrait False.
★★ Exercice 6 — Où est-il ? #
▶ Écrire :
-
premiere_voyelle(mot): l’indice de la première voyelle (a,e,i,o,u,y) de la chaînemot, ou-1s’il n’y en a pas ; -
dernier_indice(t, x): l’indice de la dernière occurrence dexdans le tableaut, ou-1sixest absent.
>>> premiere_voyelle("schtroumpf")
5
>>> dernier_indice([4, 1, 4, 2], 4)
2
Coup de pouce
Première voyelle : parcourir par indice, tester mot[i] in "aeiouy" et s’arrêter dès qu’on trouve. Dernière occurrence : soit parcourir tout le tableau en mémorisant le dernier indice rencontré, soit parcourir les indices à l’envers.
Corrigé
Pour la première voyelle, on renvoie dès qu’on trouve. Pour la dernière occurrence, en parcourant de gauche à droite, on ne peut pas s’arrêter tôt : une autre occurrence peut encore venir. On retient donc le dernier indice vu, jusqu’au bout du tableau.
def premiere_voyelle(mot):
for i in range(len(mot)):
if mot[i] in "aeiouy":
return i
return -1
def dernier_indice(t, x):
resultat = -1
for i in range(len(t)):
if t[i] == x:
resultat = i # on ecrase : on garde le dernier
return resultat
Autre méthode pour dernier_indice : parcourir les indices à l’envers, du dernier au premier : la première occurrence rencontrée est alors la dernière du tableau, et on peut s’arrêter dès qu’on la trouve.
def dernier_indice(t, x):
for i in range(len(t) - 1, -1, -1):
if t[i] == x:
return i
return -1
★★ Exercice 7 — Recherche sous condition #
▶ Écrire premier_negatif(t) qui renvoie le premier élément strictement négatif rencontré, ou None s’il n’y en a pas.
>>> premier_negatif([4, 7, -2, 9, -5])
-2
Coup de pouce
Même structure que a_un_multiple : on renvoie l’élément dès que la condition est vraie. Que renvoyer si la boucle se termine sans succès ?
Corrigé
Recherche séquentielle : on renvoie l’élément dès que la condition x < 0 est vraie ; si la boucle se termine sans succès, on renvoie None.
def premier_negatif(t):
for x in t:
if x < 0:
return x
return None
Minimum, maximum et champion#
★ Exercice 8 — Le plus petit #
• essentiel
▶ Écrire minimum(t) (tableau non vide), sans min. Préciser l’invariant de votre boucle. Pourquoi serait-il faux d’initialiser le champion à 0 ? (Penser au tableau [3, 8, 5].)
Coup de pouce
Reprendre le patron du champion du cours en changeant le sens de la comparaison. Pour l’invariant, compléter : « à chaque tour, m est … des éléments déjà visités ».
Corrigé
def minimum(t):
m = t[0]
for x in t:
if x < m:
m = x
return m
Invariant : à chaque tour, m est le minimum des éléments déjà visités. Initialiser m à 0 serait faux : sur [3, 8, 5], aucun élément n’est inférieur à 0, et la fonction renverrait 0, qui n’est même pas dans le tableau (c’est le défaut de l’exercice « Lecture de trace »). On initialise avec un élément existant : t[0].
▷ Erreur fréquente. placer m = t[0] dans la boucle : le champion est remis à t[0] à chaque tour, et la fonction renvoie seulement le plus petit de t[0] et du dernier élément.
★ Exercice 9 — Le mot le plus long : lignes à remettre dans l’ordre #
Les lignes de la fonction mot_le_plus_long(mots) (tableau de chaînes non vide) ont été mélangées et leur indentation a été perdue. Les recopier dans le bon ordre et correctement indentées, puis ▶ tester sur ["chat", "girafe", "ours", "souris"]. Pourquoi obtient-on "girafe" et non "souris", qui a pourtant la même longueur ?
return champion
champion = mot
def mot_le_plus_long(mots):
if len(mot) > len(champion):
champion = mots[0]
for mot in mots:
Coup de pouce
La ligne def vient en premier. Qu’est-ce qui doit être fait une seule fois avant la boucle, à chaque tour (et seulement sous condition), une seule fois après ?
Corrigé
def mot_le_plus_long(mots):
champion = mots[0]
for mot in mots:
if len(mot) > len(champion):
champion = mot
return champion
À noter : champion = mots[0] se place avant la boucle (initialisation du champion) ; return champion est au niveau de la boucle, après elle (sinon on renverrait dès le premier tour). Sur l’exemple, on obtient "girafe" : quand arrive "souris", le test len(mot) > len(champion) compare 6 > 6, qui est faux. La comparaison stricte garde donc le premier mot de longueur maximale.
★★ Exercice 10 — La position du champion #
▶ Écrire indice_du_min(t) qui renvoie l’indice du plus petit élément (le premier en cas d’égalité).
Coup de pouce
Retenir l’indice du champion, pas sa valeur : parcourir par indice et comparer t[i] à la valeur du champion. Faut-il < ou <= pour garder le premier en cas d’égalité ?
Corrigé
On retient l’indice du champion, i_min, initialisé à 0 ; on parcourt par indice et l’on compare t[i] à la valeur du champion, t[i_min].
def indice_du_min(t):
i_min = 0
for i in range(len(t)):
if t[i] < t[i_min]: # strict : on garde le PREMIER en cas d'egalite
i_min = i
return i_min
▷ Erreur fréquente. écrire t[i] <= t[i_min] : en cas d’égalité, le champion est remplacé, et l’on renvoie le dernier indice du minimum.
★★ Exercice 11 — Amplitude #
▶ Écrire amplitude(t) qui renvoie la différence entre le plus grand et le plus petit élément d’un tableau non vide. Combien de parcours votre solution effectue-t-elle ?
Coup de pouce
Il faut deux « champions » : le plus grand et le plus petit. Peut-on les mettre à jour dans la même boucle ?
Corrigé
def amplitude(t):
plus_petit = t[0]
plus_grand = t[0]
for x in t:
if x < plus_petit:
plus_petit = x
if x > plus_grand:
plus_grand = x
return plus_grand - plus_petit
Cette solution fait un seul parcours (on cherche min et max en même temps). Deux parcours séparés donneraient le même résultat, en deux fois plus de tours.
★★ Exercice 12 — Moyenne de fin de trimestre #
▶ Les notes d’un élève sont dans un tableau. Écrire moyenne_sans_pire(t) qui calcule la moyenne après avoir retiré la plus mauvaise note. On supposera au moins deux notes.
>>> moyenne_sans_pire([8, 12, 15, 5])
11.666666666666666
Coup de pouce
Faut-il vraiment retirer la note du tableau ? Une fois la pire note enlevée, que deviennent la somme des notes et leur nombre ?
Corrigé
On retire une fois la plus mauvaise note de la somme, et on divise par len(t) - 1. La somme et la pire note se calculent dans le même parcours.
def moyenne_sans_pire(t):
pire = t[0]
total = 0
for x in t:
total = total + x
if x < pire:
pire = x
return (total - pire) / (len(t) - 1)
★★★ Exercice 13 — Le deuxième plus grand #
≈ 20 min
▶ Écrire deuxieme_max(t) qui renvoie le deuxième plus grand élément distinct d’un tableau (on suppose au moins deux valeurs distinctes), en un seul parcours.
>>> deuxieme_max([3, 9, 9, 7, 2])
7
Coup de pouce
Garder deux champions : premier (le plus grand vu) et second. Quand un élément bat premier, que devient l’ancien premier ? Et que faire d’un élément égal à premier ?
Coup de pouce 2 (début de solution)
premier = None
second = None
for x in t:
puis distinguer deux cas : x bat premier ; x se place entre second et premier.
Corrigé
On tient à jour deux champions : le plus grand (premier) et le deuxième plus grand distinct (second), initialisés à None (« pas encore de champion »). Pour chaque élément x, deux cas utiles : x bat le record (l’ancien premier passe deuxième) ; ou x est strictement plus petit que premier et bat second. Un élément égal à premier ne change rien.
def deuxieme_max(t):
premier = None # plus grand vu
second = None # 2e plus grand DISTINCT
for x in t:
if premier == None or x > premier: # nouveau record
second = premier
premier = x
elif x < premier: # entre second et premier ?
if second == None or x > second:
second = x
return second
On écrit ici == None ; le chapitre Spécifier et mettre au point ses programmes présentera l’écriture recommandée is None.
Invariants de boucle#
★ Exercice 14 — Que contient la variable ? #
• essentiel
On considère la fonction suivante :
def f(t):
c = 0
for x in t:
if x % 2 == 0:
c = c + 1
return c
-
Énoncer l’invariant de la boucle : que contient
cà chaque tour ? -
En déduire ce que calcule la fonction.
Coup de pouce
Faire la trace sur un petit tableau, par exemple [3, 4, 7, 8] : après chaque tour, que compte c parmi les éléments déjà visités ?
Corrigé
1. Invariant : à chaque tour, c contient le nombre d’éléments pairs déjà visités.
2. À la fin, tous les éléments ont été visités : la fonction renvoie le nombre d’éléments pairs du tableau.
▷ Erreur fréquente. énoncer l’invariant sur « tous les éléments du tableau » : il ne porte que sur les éléments déjà visités ; c’est seulement à la sortie de la boucle que ce sont tous les éléments.
★★ Exercice 15 — Énoncer un invariant #
On reprend la fonction produit(t) (initialisation p = 1, puis p = p * x à chaque tour).
-
Énoncer l’invariant de la boucle (ce que contient
pà chaque tour). -
Expliquer en une phrase pourquoi cet invariant garantit que le résultat final est correct.
Coup de pouce
S’inspirer de l’invariant du champion : « p contient … des éléments déjà visités ». Que sont les éléments déjà visités à la sortie de la boucle ?
Corrigé
1. Invariant : à chaque tour, p contient le produit des éléments déjà visités (et p = 1, produit vide, avant le premier tour).
2. Comme l’invariant est vrai à chaque tour, il l’est encore au dernier : quand tous les éléments ont été visités, p est le produit de tout le tableau — le résultat est donc correct.
★★★ Exercice 16 — Une preuve d’invariant en deux étapes #
≈ 15 min
On considère nb_positifs(t), qui compte les éléments strictement positifs (initialisation c = 0 ; à chaque tour, c = c + 1 si x > 0). Soit la propriété $\(P : \text{«~\texttt{c} contient le nombre d'éléments strictement positifs \textbf{déjà visités}~».}\)$ En suivant la méthode du cours, démontrer que \(P\) est un invariant :
-
Initialisation : montrer que \(P\) est vraie avant le premier tour.
-
Hérédité : en supposant \(P\) vraie avant un tour, montrer qu’elle l’est encore après (distinguer les cas
x > 0etx <= 0). -
Conclusion : expliquer pourquoi la fonction renvoie bien le nombre d’éléments positifs du tableau entier.
Coup de pouce
Initialisation : avant le premier tour, combien d’éléments ont été visités, et combien de positifs parmi eux ? Hérédité : partir de « c = nombre de positifs déjà visités » et regarder l’effet du nouvel élément x.
Coup de pouce 2 (début de solution)
Hérédité, cas x > 0 : le nombre de positifs déjà visités augmente de 1, et l’instruction c = c + 1 fait de même. Rédiger ensuite le cas x <= 0, puis la conclusion.
Corrigé
1. Initialisation. Avant le premier tour, aucun élément n’a été visité et c = 0 : il y a bien 0 élément positif parmi les éléments visités (il n’y en a aucun). \(P\) est vraie.
2. Hérédité. Supposons \(P\) vraie avant un tour : c est le nombre de positifs déjà vus. On visite x, deux cas :
-
x > 0: on faitc = c + 1.xétant positif, le nombre de positifs vus augmente de 1 :cest à jour. -
x <= 0:cne change pas.xn’étant pas positif, le nombre de positifs vus ne change pas non plus :cest à jour.
Dans les deux cas, \(P\) est encore vraie après le tour.
3. Conclusion. \(P\) est vraie au départ et se conserve : elle est donc vraie à chaque tour, en particulier à la fin, quand tous les éléments ont été visités. c contient alors le nombre d’éléments strictement positifs de tout le tableau. \(\square\)
Le coût : linéaire ou quadratique ?#
★ Exercice 17 — Compter les tours #
• essentiel
Pour chaque fonction, dire combien de tours de boucle sont effectués pour un tableau de n éléments, et si le coût est linéaire ou quadratique.
# (a) # (b)
def f(t): def g(t):
s = 0 c = 0
for x in t: for i in range(len(t)):
s = s + x for j in range(len(t)):
return s if t[i] == t[j]:
c = c + 1
return c
Coup de pouce
Combien de tours fait une boucle for sur un tableau de n éléments ? Dans (b), la boucle intérieure est exécutée en entier à chaque tour de la boucle extérieure.
Corrigé
(a) n tours de boucle : coût linéaire. (b) deux boucles imbriquées sur t : \(n \times n = n^2\) tours : coût quadratique.
▷ Erreur fréquente. ne compter que les \(n\) tours de la boucle intérieure : elle est exécutée en entier à chacun des \(n\) tours de la boucle extérieure.
★★ Exercice 18 — Min et max en une seule passe #
▶ Écrire mini_maxi(t) qui renvoie le p-uplet (min, max) en un seul parcours du tableau. Comparer au coût de deux parcours séparés.
Coup de pouce
Deux champions initialisés avec t[0], et deux tests dans le même tour de boucle. Combien de tours font deux parcours séparés ?
Corrigé
def mini_maxi(t):
mini = t[0]
maxi = t[0]
for x in t:
if x < mini:
mini = x
if x > maxi:
maxi = x
return mini, maxi
Un seul parcours (\(n\) tours) au lieu de deux (\(2n\) tours) : deux fois moins de tours de boucle, mais autant de comparaisons (deux par tour, soit \(2n\) dans les deux cas). Le coût reste linéaire.
★★ Exercice 19 — Détecter un doublon #
▶ Écrire a_un_doublon(t) qui renvoie True si (au moins) deux éléments de t sont égaux. Quel est le coût de votre solution (en nombre de comparaisons dans le pire cas) ? au-delà du programme
Coup de pouce
Comparer chaque élément à ceux qui sont après lui : deux boucles imbriquées sur les indices. Attention à ne jamais comparer un élément à lui-même.
Corrigé
Deux boucles imbriquées sur les indices : on compare chaque élément à ceux qui sont après lui (j part de i + 1), et l’on s’arrête dès qu’on trouve deux éléments égaux.
def a_un_doublon(t):
for i in range(len(t)):
for j in range(i + 1, len(t)): # on ne compare chaque paire qu'une fois
if t[i] == t[j]:
return True
return False
Dans le pire cas (aucun doublon), on examine toutes les paires, soit environ \(\dfrac{n^2}{2}\) comparaisons : coût quadratique. au-delà du programme
★★★ Exercice 20 — Deux tableaux #
≈ 15 min
▶ Écrire element_commun(t1, t2) qui renvoie True si les deux tableaux ont (au moins) un élément en commun. Combien de fois, dans le pire cas, compare-t-on deux éléments si t1 et t2 ont chacun n éléments ? Quel est le coût ? au-delà du programme
Coup de pouce
Pour chaque élément de t1, chercher s’il est dans t2 : une recherche séquentielle à l’intérieur d’une autre boucle. Le pire cas : aucun élément commun.
Coup de pouce 2 (début de solution)
for x in t1:
for y in t2:
if x == y:
Corrigé
def element_commun(t1, t2):
for x in t1:
for y in t2:
if x == y:
return True
return False
Dans le pire cas (aucun élément commun), on compare chaque élément de t1 à chaque élément de t2, soit \(n \times n = n^2\) comparaisons : coût quadratique. au-delà du programme
★★★ Exercice 21 — Moyenne, variance — et le piège du coût #
≈ 30 min
C’est l’exercice central du chapitre. La variance mesure la dispersion : \(V = \dfrac{1}{n}\displaystyle\sum_i (x_i - m)^2\), où \(m\) est la moyenne.
-
▶ Écrire
moyenne(t)(un parcours). -
▶ Écrire
variance_naive(t)en appelantmoyenne(t)à l’intérieur de la boucle. La fonction est-elle correcte ? -
Combien de fois au total
variance_naiveadditionne-t-elle des nombres pour un tableau denéléments ? En déduire son coût. -
▶ Écrire
variance(t)qui calcule la moyenne une seule fois, avant la boucle. Quel est son coût ? -
Vérifier que les deux versions donnent le même résultat sur
[2, 4, 4, 4, 5, 5, 7, 9](la variance vaut4.0). Laquelle utiliseriez-vous sur un million de valeurs, et pourquoi ?
Coup de pouce
Question 3 : moyenne(t) fait n additions, et variance_naive l’appelle à chaque tour de sa boucle. Combien de tours fait cette boucle ?
Coup de pouce 2 (début de solution)
def variance(t):
m = moyenne(t)
s = 0
for x in t:
Corrigé
1, 2, 4. Les trois fonctions :
def moyenne(t): # 1.
s = 0
for x in t:
s = s + x
return s / len(t)
def variance_naive(t): # 2.
n = len(t)
s = 0
for x in t:
s = s + (x - moyenne(t)) ** 2 # moyenne(t) recalculee a chaque tour
return s / n
def variance(t): # 4.
n = len(t)
m = moyenne(t) # calculee UNE seule fois
s = 0
for x in t:
s = s + (x - m) ** 2
return s / n
2. variance_naive est correcte : elle calcule bien la variance. 3. À chacun des n tours, moyenne(t) effectue n additions : total \(\approx n \times n = n^2\) additions. Coût quadratique. 4. variance fait un parcours pour la moyenne puis un pour la somme : \(\approx 2n\) opérations, coût linéaire. 5. Les deux renvoient 4.0 sur l’exemple. Sur un million de valeurs, on utilise variance : la version naïve demanderait \(\approx 10^{12}\) opérations (des heures), la version efficace \(\approx 2\times 10^6\) (immédiat).
Synthèse : petits problèmes#
★★ Exercice 22 — Relevé météo #
▶ Un tableau temperatures donne la température de chaque jour du mois.
-
jour_le_plus_chaud(temperatures): l’indice (le numéro du jour, à partir de 0) du maximum. -
nb_jours_gel(temperatures): le nombre de jours où la température a été strictement négative. -
plus_longue_serie_chaude(temperatures, seuil): la longueur de la plus longue série consécutive de jours au-dessus deseuil. au-delà du programme
Coup de pouce
1 : c’est la position du champion. 2 : un compteur. 3 : deux variables, la longueur de la série en cours et la meilleure longueur vue ; que devient la série en cours un jour plus froid ?
Coup de pouce 2 (début de solution)
courante = 0
record = 0
for temp in temperatures:
if temp > seuil:
Corrigé
1 : position du champion (on retient l’indice du maximum) ; 2 : un compteur ; 3 : deux variables, la longueur de la série en cours (remise à 0 un jour plus froid) et le record.
def jour_le_plus_chaud(temperatures):
i_max = 0
for i in range(len(temperatures)):
if temperatures[i] > temperatures[i_max]:
i_max = i
return i_max
def nb_jours_gel(temperatures):
c = 0
for temp in temperatures:
if temp < 0:
c = c + 1
return c
def plus_longue_serie_chaude(temperatures, seuil): # au-dela du programme
record = 0
courante = 0
for temp in temperatures:
if temp > seuil:
courante = courante + 1
if courante > record:
record = courante
else:
courante = 0
return record
★★ Exercice 23 — Vers le bac — contrôle de saisie #
▶ Un tableau notes est censé ne contenir que des entiers entre 0 et 20.
-
toutes_valides(notes):Truesi toutes les notes sont dans[0 ; 20],Falsedès qu’une note sort de l’intervalle (s’arrêter tôt). -
indices_invalides(notes): le tableau des indices des notes hors intervalle.
Coup de pouce
1 : renvoyer False dès qu’une note sort de l’intervalle, et True seulement après la boucle. 2 : partir d’un tableau vide et y ajouter des indices, donc parcourir par indice.
Corrigé
1 : recherche séquentielle d’une note invalide : on renvoie False dès qu’on en trouve une, True seulement après la boucle. 2 : on garde les indices des notes hors de l’intervalle.
def toutes_valides(notes):
for note in notes:
if note < 0 or note > 20:
return False # une seule note hors bornes suffit : on s'arrete
return True
def indices_invalides(notes):
return [i for i in range(len(notes)) if notes[i] < 0 or notes[i] > 20]
Pour indices_invalides, on parcourt par indice (c’est l’indice qu’on garde, pas la note). Autre méthode : la boucle avec append que la compréhension condense.
def indices_invalides(notes):
resultat = []
for i in range(len(notes)):
if notes[i] < 0 or notes[i] > 20:
resultat.append(i)
return resultat
★★ Exercice 24 — Une recherche selon un assistant d’IA #
Un élève demande à un assistant d’IA : « Écris une fonction Python qui dit si une valeur x est présente dans un tableau t. » Voici la réponse obtenue.
def est_present(t, x):
"""Renvoie True si x est dans t, False sinon."""
for element in t:
if element == x:
return True
else:
return False
« La boucle parcourt le tableau : dès qu’un élément est égal à x, la fonction renvoie True, sinon elle renvoie False. Le coût est linéaire dans le pire des cas. »
-
La réponse est-elle correcte ? Faire la trace de
est_present([3, 8, 5], 5). -
Localiser et corriger l’erreur.
-
Quelle vérification simple, faite avant de faire confiance à la réponse, aurait suffi à détecter l’erreur ?
Coup de pouce
Faire la trace pas à pas : au premier tour, element vaut 3. Lequel des deux return est exécuté ? La boucle continue-t-elle ?
Corrigé
1. Non. Trace de est_present([3, 8, 5], 5) : premier tour, element = 3 ; 3 == 5 est faux, on passe dans le else et la fonction renvoie False — alors que 5 est bien dans le tableau. La fonction ne regarde en fait que le premier élément (elle ne répond True que pour x = 3). 2. L’erreur est le else: return False dans la boucle : on conclut à l’absence avant d’avoir tout regardé. Le return False doit être après la boucle :
def est_present(t, x):
for element in t:
if element == x:
return True
return False # parcours fini sans succes : absent
Avec cette correction, est_present([3, 8, 5], 5) renvoie True et est_present([3, 8, 5], 7) renvoie False. 3. Tester la fonction sur un exemple où x n’est pas en première position : un seul appel suffisait. Un return False placé dans un for est presque toujours suspect.
Entraînement#
Exercices courts pour s’entraîner aux gestes de base, chacun avec plusieurs données. Ils font tous partie du parcours essentiel.
★ Exercice 25 — Dérouler la recherche du maximum #
• essentiel
On considère la fonction du cours :
def maximum(t):
m = t[0]
for x in t:
if x > m:
m = x
return m
Sans machine, donner la valeur de m après chaque tour de boucle, puis le résultat, pour : a) [5, 2, 8, 1, 8] ; b) [-4, -9, -2, -7] ; c) [7].
Coup de pouce
Un tableau de trace à deux colonnes, x et m, une ligne par tour. Avant le premier tour, m vaut déjà t[0]. m ne change que si x est strictement plus grand.
Corrigé
Valeurs de m après chaque tour : a) 5, 5, 8, 8, 8 : résultat 8 (le second 8 ne remplace pas le premier : 8 > 8 est faux). b) -4, -4, -2, -2 : résultat -2. c) 7 : un seul tour, résultat 7.
▷ Erreur fréquente. partir de m = 0 au lieu de t[0] : sur b), m resterait à 0, qui n’est pas dans le tableau.
★ Exercice 26 — Recherche séquentielle : combien de tours ? #
• essentiel
Avec la fonction est_present(t, x) du cours (on renvoie True dès qu’on trouve, False après la boucle), donner sans machine le résultat et le nombre de tours de boucle effectués pour chaque appel : a) est_present([4, 7, 1, 9], 1) ; b) est_present([4, 7, 1, 9], 5) ; c) est_present([], 3) ; d) est_present([2, 2, 2], 2). Lequel de ces appels illustre le pire cas ?
Coup de pouce
Compter les éléments examinés : la boucle s’arrête au premier élément égal à x. Si x est absent, combien d’éléments faut-il examiner avant de répondre ?
Corrigé
a) True en 3 tours (1 est le troisième élément). b) False en 4 tours : 5 est absent, il faut tout examiner. c) False en 0 tour : le tableau est vide. d) True en 1 tour : le meilleur cas. Le pire cas est b) : l’élément est absent et l’on examine les \(n\) éléments.