Problèmes de sous-tableaux
Les sous-tableaux sont des segments contigus d'un tableau. Dans cette section, nous allons explorer deux problèmes classiques : trouver un sous-tableau avec une moyenne maximale et trouver le plus grand sous-tableau avec autant de 0 que de 1.
Sous-tableau de moyenne maximale
Étant donné un tableau tab[] et deux entiers X et Y. La tâche consiste à trouver un sous-tableau de taille supérieure ou égale à X et d'au plus Y, qui contient la moyenne maximale (moyenne des éléments du sous-tableau).
tab = [1, 2, 3, 4, 5] X = 2, Y = 3
4.5
tab = [6, 7, 8, 3, 2, 4, 2] X = 2, Y = 4
7.5
Parcourez tous les sous-tableaux de taille allant de X à Y et trouvez la moyenne maximale parmi tous ces sous-tableaux.
ApprocheNous pouvons utiliser deux boucles imbriquées pour itérer sur tous les sous-tableaux dont la taille varie de X à Y.
Pour réduire la complexité, nous pouvons utiliser un tableau de sommes préfixes (cumulatives) pour obtenir la somme de tous les sous-tableaux en complexité O(1).
1. Calculer le tableau des sommes cumulatives: cumule[i] = somme(tab[0..i])
2. Initialiser maximum = 0
3. Pour i de 0 à n-1:
Pour j de i+X-1 à min(i+Y-1, n-1):
somme = cumule[j] - (cumule[i-1] si i>0)
moyenne = somme / (j-i+1)
maximum = max(maximum, moyenne)
4. Retourner maximumdef MoyenneSousTab(tab, n, x, y):
"""
Trouve la moyenne maximale d'un sous-tableau de taille entre x et y
Paramètres:
tab: tableau d'entrée
n: taille du tableau
x: taille minimale du sous-tableau
y: taille maximale du sous-tableau
"""
# calculer la somme cumulative (préfixe)
cumule = [0] * n
cumule[0] = tab[0]
for i in range(1, n):
cumule[i] = cumule[i - 1] + tab[i]
maximum = 0
# parcourir tous les sous-tableaux
for i in range(n):
j = i + x - 1 # premier sous-tableau de taille x commençant à i
# sous-tableaux de taille de X à Y
while j < i + y and j < n:
# récupérer la somme du sous-tableau
somme = cumule[j]
if i > 0:
somme -= cumule[i - 1]
# calculer la moyenne
moyenneCourante = somme / (j - i + 1)
# stocker le maximum
maximum = max(maximum, moyenneCourante)
j += 1
return maximum
# Test
T = [1, 2, 3, 4, 5]
X = 2
Y = 3
print(f"Moyenne maximale pour {T} avec X={X}, Y={Y}:")
print(MoyenneSousTab(T, len(T), X, Y))4.5
Plus grand sous-tableau avec autant de 0 que de 1
Étant donné un tableau contenant uniquement des 0 et des 1, recherchez le plus grand sous-tableau contenant le même nombre de 0 et de 1. La complexité attendue est O(n).
tab = [1, 0, 1, 1, 1, 0, 0]
1 à 6
tab = [0, 0, 1, 1, 0]
0 à 3 ou 1 à 4
Méthode 1 : Approche naïve (O(n²))
Une méthode simple consiste à utiliser deux boucles imbriquées :
- La boucle extérieure choisit un point de départ i.
- La boucle intérieure considère tous les sous-tableaux à partir de i.
- Si la taille d'un sous-tableau est supérieure à la taille maximale jusqu'à présent, mettre à jour la taille maximale.
- Si la somme devient 0 (autant de 0 que de 1), alors la taille de ce sous-tableau est comparée à la plus grande taille jusqu'à présent.
Complexité : O(n²)
def equilibre_naif(tab, n):
"""
Trouve le plus grand sous-tableau avec autant de 0 que de 1
Version naïve - O(n²)
"""
somme = 0
max_taille = -1
debut = -1
for i in range(0, n):
# Convertir 0 en -1 pour faciliter le calcul
somme = -1 if (tab[i] == 0) else 1
# parcourir les sous-tableaux à partir de i
for j in range(i + 1, n):
# mettre à jour la somme
if tab[j] == 0:
somme += -1
else:
somme += 1
# Si somme devient 0, on a autant de 0 que de 1
if somme == 0 and max_taille < j - i + 1:
max_taille = j - i + 1
debut = i
if max_taille == -1:
print("Aucun sous-tableau trouvé")
return -1
else:
print(f"Plus grand sous-tableau de {debut} à {debut + max_taille - 1}")
return max_taille
# Test
T = [0, 0, 1, 1, 0]
print("Test avec [0, 0, 1, 1, 0] :")
equilibre_naif(T, len(T))Plus grand sous-tableau de 0 à 3
Méthode 2 : Approche optimisée avec table de hachage (O(n))
- Considérons toutes les valeurs 0 comme -1. Le problème se réduit maintenant à trouver la longueur maximale du sous-tableau avec somme = 0.
- Créez un tableau temporaire sommeLeft[] de taille n. Stocke la somme de tous les éléments de tab[0] à tab[i] dans sommeLeft[i]. Cela peut être fait en un temps O(n).
- Il existe deux cas : le sous-tableau de sortie peut commencer à partir de l'index 0 ou peut-être à partir d'un autre index. Nous renverrons le maximum des valeurs obtenues par ces deux cas.
- Pour trouver la longueur maximale du sous-tableau à partir de l'index 0, parcourez sommeLeft[] et recherchez le maximum i où sommeLeft[i] = 0.
- Pour trouver le sous-tableau où la somme est 0 et l'index de début n'est pas 0, nous devons trouver deux indices i et j dans sommeLeft[] tels que sommeLeft[i] = sommeLeft[j] et j-i est maximum.
- Pour résoudre ce problème, nous pouvons créer une table de hachage (dictionnaire en Python) qui stocke la première occurrence de chaque valeur de somme.
- Complexité : O(n)
def equilibre_optimale(tab, n):
"""
Trouve le plus grand sous-tableau avec autant de 0 que de 1
Version optimisée - O(n) avec table de hachage
"""
# Remplacer 0 par -1
for i in range(n):
if tab[i] == 0:
tab[i] = -1
# Dictionnaire pour stocker la première occurrence de chaque somme
# La clé est la somme, la valeur est l'index
hash_map = {}
somme = 0
max_taille = 0
fin = -1
for i in range(n):
somme += tab[i]
# Si la somme est 0, le sous-tableau de 0 à i a autant de 0 que de 1
if somme == 0:
max_taille = i + 1
fin = i
# Si la somme a déjà été vue, le sous-tableau entre la première occurrence
# et l'index actuel a une somme de 0
if somme in hash_map:
if max_taille < i - hash_map[somme]:
max_taille = i - hash_map[somme]
fin = i
else:
# Première occurrence de cette somme
hash_map[somme] = i
if max_taille == 0:
print("Aucun sous-tableau trouvé")
return 0
else:
debut = fin - max_taille + 1
print(f"Plus grand sous-tableau de {debut} à {fin}")
return max_taille
# Test avec les exemples
print("Exemple 1: [1, 0, 1, 1, 1, 0, 0]")
T1 = [1, 0, 1, 1, 1, 0, 0]
equilibre_optimale(T1, len(T1))
print("\nExemple 2: [0, 0, 1, 1, 0]")
T2 = [0, 0, 1, 1, 0]
equilibre_optimale(T2, len(T2))Exemple 1: [1, 0, 1, 1, 1, 0, 0] Plus grand sous-tableau de 1 à 6 Exemple 2: [0, 0, 1, 1, 0] Plus grand sous-tableau de 0 à 3
En remplaçant 0 par -1, le problème devient : trouver le plus long sous-tableau dont la somme est 0.
Si la somme cumulée jusqu'à l'index i est S, et que cette même somme S a déjà été vue à l'index j, alors la somme du sous-tableau de j+1 à i est 0.
Le dictionnaire stocke la première occurrence de chaque somme pour maximiser la longueur.
- Les sous-tableaux sont des segments contigus d'un tableau.
- L'utilisation de sommes préfixes permet de calculer la somme d'un sous-tableau en O(1).
- Pour le problème des 0 et 1, remplacer 0 par -1 transforme le problème en recherche de somme nulle.
- La table de hachage (dictionnaire) est essentielle pour atteindre une complexité O(n).
- La complexité optimale pour le second problème est O(n).
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.