Problème de l'élément pic (Peak Element)
Un élément pic dans un tableau est un élément qui est supérieur à ses voisins gauche et droit.
- Si le tableau est trié dans l'ordre croissant, l'élément pic est le dernier élément du tableau.
- Si le tableau est trié dans l'ordre décroissant, l'élément pic est le premier élément du tableau.
Remarque : Un tableau peut contenir plusieurs éléments pic.
T = [1, 4, 3, 6, 7, 5]
4 ou 7
Trouver un élément pic
Étant donné un tableau d'entiers, écrivez un algorithme qui retourne un élément pic.
Un élément de tableau est un pic s'il est supérieur à ses voisins gauche et droite.
Solution 1 : Approche linéaire (O(n))
Parcourir le tableau et trouver un élément supérieur à ses voisins.
Parcourir le tableau de i=1 à n-2:
si tab[i] > tab[i-1] et tab[i] > tab[i+1]:
retourner tab[i]
# Si aucun élément intérieur n'est un pic
si tab[0] > tab[1]:
retourner tab[0]
sinon:
retourner tab[n-1]Complexité : O(n) temps, O(1) espace
def pic_lineaire(tab):
"""
Recherche linéaire d'un élément pic
Complexité : O(n)
"""
n = len(tab)
# Cas particuliers
if n == 1:
return tab[0]
if n == 2:
return max(tab[0], tab[1])
# Recherche d'un pic à l'intérieur du tableau
for i in range(1, n-1):
if tab[i] > tab[i-1] and tab[i] > tab[i+1]:
return tab[i]
# Si aucun pic intérieur, le premier ou dernier élément est un pic
if tab[0] > tab[1]:
return tab[0]
else:
return tab[n-1]
tab = [1, 4, 3, 6, 7, 5]
print(f"Tableau: {tab}")
print(f"Pic trouvé (linéaire): {pic_lineaire(tab)}")Solution 2 : Recherche dichotomique récursive (O(log n))
On peut utiliser une approche de type "diviser pour régner" pour trouver un pic en O(log n).
- Calculer l'indice du milieu.
- Si l'élément du milieu est un pic, le retourner.
- Sinon, si l'élément du milieu est inférieur à son voisin gauche, chercher dans la moitié gauche.
- Sinon, chercher dans la moitié droite.
Cette approche fonctionne car un pic existe toujours dans la direction de la montée.
Fonction pic_recursif(tab, debut, fin):
si debut == fin:
retourner tab[debut]
milieu = (debut + fin) // 2
si tab[milieu] > tab[milieu-1] et tab[milieu] > tab[milieu+1]:
retourner tab[milieu]
sinon si tab[milieu] > tab[milieu-1]:
# On est dans une montée vers la droite
retourner pic_recursif(tab, milieu+1, fin)
sinon:
# On est dans une montée vers la gauche
retourner pic_recursif(tab, debut, milieu-1)Complexité : O(log n) temps, O(log n) espace (pile récursive)
def pic_recursif(tab, debut, fin):
"""
Recherche dichotomique récursive d'un élément pic
Complexité : O(log n)
"""
if debut == fin:
return tab[debut]
milieu = (debut + fin) // 2
# Gestion des bords
if milieu == 0:
return max(tab[0], tab[1])
if milieu == len(tab) - 1:
return max(tab[-2], tab[-1])
# Vérifier si l'élément du milieu est un pic
if tab[milieu] > tab[milieu-1] and tab[milieu] > tab[milieu+1]:
return tab[milieu]
# Chercher dans la direction de la montée
if tab[milieu] > tab[milieu-1]:
# Montée vers la droite
return pic_recursif(tab, milieu+1, fin)
else:
# Montée vers la gauche
return pic_recursif(tab, debut, milieu-1)
tab = [1, 4, 3, 6, 7, 5]
print(f"Tableau: {tab}")
print(f"Pic trouvé (récursif): {pic_recursif(tab, 0, len(tab)-1)}")Solution 3 : Recherche dichotomique itérative (O(log n))
Initialiser debut = 0, fin = n-1
Tant que debut ≤ fin:
milieu = (debut + fin) // 2
si (milieu == 0 ou tab[milieu] > tab[milieu-1]) et
(milieu == n-1 ou tab[milieu] > tab[milieu+1]):
retourner tab[milieu]
si milieu > 0 et tab[milieu-1] > tab[milieu]:
fin = milieu - 1
sinon:
debut = milieu + 1
retourner tab[debut]Complexité : O(log n) temps, O(1) espace
def pic_iteratif(tab):
"""
Recherche dichotomique itérative d'un élément pic
Complexité : O(log n) temps, O(1) espace
"""
n = len(tab)
debut, fin = 0, n - 1
while debut <= fin:
milieu = (debut + fin) // 2
# Vérifier si l'élément du milieu est un pic
gauche_ok = (milieu == 0 or tab[milieu] > tab[milieu - 1])
droite_ok = (milieu == n - 1 or tab[milieu] > tab[milieu + 1])
if gauche_ok and droite_ok:
return tab[milieu]
# Chercher dans la direction de la montée
if milieu > 0 and tab[milieu - 1] > tab[milieu]:
fin = milieu - 1
else:
debut = milieu + 1
return tab[debut]
tab = [1, 4, 3, 6, 7, 5]
print(f"Tableau: {tab}")
print(f"Pic trouvé (itératif): {pic_iteratif(tab)}")Tableau: [1, 4, 3, 6, 7, 5] Pic trouvé (linéaire): 7 Pic trouvé (récursif): 7 Pic trouvé (itératif): 7
Exemples supplémentaires
tab = [1, 2, 3, 4, 5]
5
tab = [5, 4, 3, 2, 1]
5
tab = [10, 5, 15, 2, 23, 90, 67]
10 ou 15 ou 90
- 1 ≤ n ≤ 10⁶
- Les éléments peuvent être des entiers quelconques
- Un pic existe toujours (les bords sont considérés comme des pics potentiels)
Comparaison des approches
| Approche | Complexité temporelle | Complexité spatiale | Avantages / Inconvénients |
|---|---|---|---|
| Linéaire | O(n) | O(1) | Simple, mais pas optimal pour les grands tableaux |
| Dichotomique récursif | O(log n) | O(log n) (pile) | Très efficace, mais utilise de la pile récursive |
| Dichotomique itératif | O(log n) | O(1) | Optimal en temps et en espace |
- Un élément pic est supérieur à ses voisins.
- Un tableau peut contenir plusieurs pics.
- La recherche dichotomique permet de trouver un pic en O(log n).
- L'approche dichotomique fonctionne car on peut toujours suivre la direction de la montée.
- Les bords du tableau sont considérés comme des pics si le premier/dernier élément est plus grand que son unique voisin.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.