Solution de Séparation des 0 et des 1 - Sujet 19 - EP NSI 2025
Énoncé du problème
Exercice 1
EXERCICE 1 (10 points)
Écrire une fonction recherche_min qui prend en paramètre un tableau de nombres tab
non vide, et qui renvoie l’indice de la première occurrence du minimum de ce tableau. Les
tableaux seront représentés sous forme de liste Python.
Exemples :
>>> recherche_min([5])
0
>>> recherche_min([2, 4, 1])
2
>>> recherche_min([5, 3, 2, 2, 4])
2
>>> recherche_min([-1, -2, -3, -3])
2
Exercice 2
EXERCICE 2 (10 points)
On considère la fonction separe ci-dessous qui prend en argument un tableau tab dont
les éléments sont des 0 et des 1 et qui sépare les 0 des 1 en plaçant les 0 en début de
tableau et les 1 à la suite.
def separe(tab):
'''Separe les 0 et les 1 dans le tableau tab'''
gauche = 0
droite = ...
while gauche < droite:
if tab[gauche] == 0 :
gauche = ...
else :
tab[gauche] = ...
tab[droite] = ...
droite = ...
return tab
Compléter la fonction separe ci-dessus.
Exemples :
>>> separe([1, 0, 1, 0, 1, 0, 1, 0])
[0, 0, 0, 0, 1, 1, 1, 1]
>>> separe([1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0])
[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1]
Description d’étapes effectuées par la fonction separe sur le tableau ci-dessous, les caractères ^ indiquent les cases pointées par les indices gauche et droite :
tab = [1, 0, 1, 0, 1, 0, 1, 0]
^ ^
- Étape 1 : on regarde la première case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l’échange avec la dernière case. Il est à présent bien positionné : on ne prend plus la dernière case en compte.
tab = [0, 0, 1, 0, 1, 0, 1, 1]
^ ^
- Étape 2 : on regarde à nouveau la première case, qui contient maintenant un 0 : ce 0 va aller dans la première partie du tableau final et est bien positionné : on ne prend plus la première case en compte.
tab = [0, 0, 1, 0, 1, 0, 1, 1]
^ ^
- Étape 3 : on regarde la seconde case, qui contient un 0 : ce 0 va aller dans la première partie du tableau final et est bien positionné : on ne prend plus la seconde case en compte.
tab = [0, 0, 1, 0, 1, 0, 1, 1]
^ ^
- Étape 4 : on regarde la troisième case, qui contient un 1 : ce 1 va aller dans la seconde partie du tableau final et on l’échange avec l’avant-dernière case. Il est à présent bien positionné : on ne prend plus l’avant-dernière case en compte.
tab = [0, 0, 1, 0, 1, 0, 1, 1]
^ ^
Et ainsi de suite…
tab = [0, 0, 0, 0, 1, 1, 1, 1]
Les contraintes ci-dessous sont ajoutées par la plateforme et ne font pas partie du sujet.
Exercice 1
Contraintes :
tabest une liste Python non vide :1 <= len(tab) <= 10^4tab[i]est un entier avec-10^6 <= tab[i] <= 10^6- les valeurs de
tabpeuvent se répéter recherche_minrenvoie un entier : l’indice de la première occurrence du minimum, donc un indice compris entre0etlen(tab) - 1
Exercice 2
Contraintes :
tabest une liste Python avec0 <= len(tab) <= 10^4- chaque élément
tab[i]vaut0ou1 tabpeut être vide ou ne contenir qu’un seul élémentseparerenvoie le tableautab, contenant les mêmes nombres de0et de1qu’en entrée, les0placés avant les1
Solution
Exercice 1 - recherche_min
L’idée. Un seul parcours du tableau suffit. On retient au fur et à mesure l’indice de la plus petite valeur rencontrée jusque-là. On part de l’indice 0, la seule case connue au début, puis on compare chaque case suivante à la valeur retenue. Le point délicat est la première occurrence : on ne change d’indice que si la nouvelle valeur est strictement plus petite, jamais si elle est égale.
Un petit exemple. Pour [5, 3, 2, 2, 4] : on part de l’indice 0 (valeur 5), puis 3 < 5 donc on retient l’indice 1, puis 2 < 3 donc on retient l’indice 2, puis le 2 d’indice 3 n’est pas strictement plus petit donc on ne bouge pas, et 4 non plus. La fonction renvoie 2.
def recherche_min(tab):
indice_min = 0
# On ne change d'indice que si la valeur est strictement plus petite :
# c'est ce qui garde la première occurrence du minimum
for i in range(1, len(tab)):
if tab[i] < tab[indice_min]:
indice_min = i
return indice_min
indice_min contient un indice, pas la valeur du minimum : c’est bien un indice que l’énoncé demande de renvoyer. La boucle démarre à 1 parce que la case 0 sert de point de départ, et le tableau est non vide donc cette case existe toujours. Si on écrivait <= au lieu de <, la fonction renverrait la dernière occurrence du minimum : sur [-1, -2, -3, -3] elle donnerait 3 au lieu de 2.
Exercice 2 - separe
L’idée. On se sert de deux indices : gauche part du début du tableau, droite part de la fin. À tout moment, ce qui est avant gauche est déjà un 0 bien placé, et ce qui est après droite est déjà un 1 bien placé. On regarde la case gauche :
- si elle contient un 0, il est déjà du bon côté : on avance
gauched’un cran ; - si elle contient un 1, on l’échange avec la case
droite, ce 1 se retrouve au bon endroit et on reculedroited’un cran.
On s’arrête quand les deux indices se rejoignent.
Comment remplir les cinq trous. droite doit démarrer sur la dernière case, donc len(tab) - 1. Pour le cas du 0 : gauche = gauche + 1. Pour le cas du 1, on échange les deux cases : comme on sait déjà que tab[gauche] vaut 1, l’échange revient à recopier tab[droite] dans tab[gauche], puis à écrire 1 dans tab[droite]. Enfin on recule : droite = droite - 1.
def separe(tab):
'''Separe les 0 et les 1 dans le tableau tab'''
gauche = 0
droite = len(tab) - 1
while gauche < droite:
if tab[gauche] == 0 :
gauche = gauche + 1
else :
# tab[gauche] vaut 1 : on échange les deux cases, donc on recopie
# tab[droite] à gauche et on écrit le 1 à droite
tab[gauche] = tab[droite]
tab[droite] = 1
droite = droite - 1
return tab
Attention : quand tab[gauche] vaut 1, on n’avance pas gauche, car la valeur qui vient d’arriver à cette place n’a pas encore été examinée. C’est pour cela que l’étape 4 de l’énoncé laisse le tableau inchangé : les cases 2 et 6 contenaient toutes les deux un 1, l’échange ne change rien, mais droite recule quand même. Comme on ne fait que des échanges, le nombre de 0 et de 1 est le même au début et à la fin.
La boucle s’arrête dès que gauche et droite se rejoignent : la case restante est la frontière entre la zone des 0 et celle des 1, elle est correcte quelle que soit sa valeur. Cela couvre aussi les petits cas : sur un tableau vide, droite vaut -1 et la boucle ne s’exécute jamais ; sur un tableau à un seul élément, gauche et droite valent 0 dès le départ. Là encore, un seul parcours suffit, chaque case n’étant regardée qu’une fois.