- Créer un sous-dossier «TP03» dans le dossier «TP_informatique_commune» de votre repertoire personnel
- Si on vous demande d'écrire un script python à la question 3\c) de l'activité 2 du TP 7 vous enregistrez ce script dans un fichier nommé «tp07_act02_q03c.py». Remarquez que l'on utilisera toujours deux chiffres décimaux pour représenter les entiers et que l'on va toujours du général vers le particulier car ainsi l'ordre alphabétique correspond à l'ordre tri chronologique.
- On rendra son code modulaire en utilisant systématiquement des fonctions
- On testera toutes ses fonctions
1. Boucles multiples dans des tableaux
On appellera tableau (de dimension deux) toute liste de liste rectangulaire.
On dira d'un tableau qu'il a la propriété \(P^{*2+1}_{/3}\) si quel que soit l'entier \(e\) de ce tableau
- soit \(2e+1\) est encore dans ce tableau;
- soit \(e\) est un multiple de \(3\) et \(e/3\) est encore dans ce tableau.
Écrire une fonction
a_prop_mul2plusone_or_div3
qui accepte un tableau en argument et retourneTrue
s'il a la propriété \(P^{*2+1}_{/3}\) si quel etFalse
sinon. Ainsi[[1, 9], [4, 3]]
a cette propriété mais pas[[1, 3], [7, 11]]
ce qui est plus facile à voir quand les tableaux sont bien saisis comme ci-dessoustab_a_la_prop = [[1, 9], [4, 3]] tab_n_a_pas_la_prop = [[1, 3], [7, 11]]
def a_prop_mul2plusone_or_div3(tab): for line in tab: for e in line: e_satis_cond = False for line2 in tab: if 2*e+1 in line2: e_satis_cond = True break if e % 3 == 0 and e // 3 in line2: e_satis_cond = True break if not e_satis_cond: return False return True A = [[0, 0], [0, 0]] assert a_prop_mul2plusone_or_div3(A) A = [[1, 3], [0, 0]] assert a_prop_mul2plusone_or_div3(A) A = [[1, 3], [7, 11]] assert not a_prop_mul2plusone_or_div3(A)
- On dira d'un élément
A[i][j]
d'un tableau à deux dimensionsA
que c'est un point selle si c'est à la fois un plus petit élément de sa ligne et un plus grand élément de sa colonne.Compléter la fonction
has_saddle_point_v0
ci-dessous afin qu'elle retourneTrue
si le tableau admet un point selle etFalse
sinon.def has_saddle_point_v0(tab): n, p = len(A), len(A[0]) for i in range(n): for j in range(p): elmt = A[i][j] for i2 in range(??): if A[i2][j] ?? elmt: return ?? for j2 in range(??): if A[i][j2] ?? elmt: return ?? return ??
def has_saddle_point_v0(tab): n, p = len(A), len(A[0]) for i in range(n): for j in range(p): elmt = A[i][j] for i2 in range(n): if A[i2][j] > elmt: return False for j2 in range(p): if A[i][j2] < elmt: return False return True
- Si on suppose le tableau
A
carré de taille \(n\times{}n\), le temps d'execution (sur une machine fixée et dans le pire des cas) de l'appelhas_saddle_point_v0(A)
est-il plutôt proportionnel à \(n\) (càd linéaire en \(n\))? Proportionnel à \(n^2\) (càd quadratique en \(n\))? Proportionnel à \(n^3\) (càd cubique en \(n\))? - Outre le tableau passé en argument, la quantité de mémoire de cet appel est-il constant, linéaire, quadratique ou cubique en \(n\)?
- Si on suppose le tableau
- Écrire une fonction
col_index_all_min_row
acceptant un tableau et un indice de ligne de ce tableau et qui retourne la liste des indices colonne des plus petits éléments de cette ligne puis se servir de cette fonction (dûment testée évidemment) pour écrire une fonctionhas_saddle_point_v1
qui utilise (un peu) plus de mémoire quehas_saddle_point_v0
mais va (nettement) plus vite (au moins dans le pire des cas et avec de gros tableaux). On précisera si la classe de complexité (dans le pire des cas) dehas_saddle_point_v0
c'est à dire si elle est constant, linéaire, quadratique ou cubique en \(n\). Écrire une fonction
saddle_point
acceptant un tableau en entrée et qui retourne la liste des points selles (chacun représenté par le couple(i,j)
) de ce tableau. Par exemple avecA = [[ 0,-1, 1], [ 0, 0, 2], [-1,-2, 3]]
l'appel
saddle_point(A)
doit retourner[(1,0), (1,1)]
.def col_index_all_min_row(A, i): row = A[i] cur_min = row[0] + 1 min_ind_list = [] for j in range(len(row)): elmt = row[j] if elmt < cur_min: cur_min, min_ind_list = elmt, [j] elif elmt == cur_min: min_ind_list.append(j) return min_ind_list A = [[0, -1, 1], [0, 0, 2], [-1, -2, 3]] assert col_index_all_min_row(A, 0) == [1] assert col_index_all_min_row(A, 1) == [0, 1] assert col_index_all_min_row(A, 2) == [1] def is_col_max(A, i, j): elmt = A[i][j] for k in range(len(A)): if A[k][j] > elmt: return False return True A = [[ 0, -1, 1], [ 0, 0, 2], [-1, -2, 3]] assert is_col_max(A, 0, 0) assert is_col_max(A, 1, 1) assert is_col_max(A, 2, 2) assert not is_col_max(A, 2, 1) def saddle_point(tab): for i in range(len(A)): L = col_index_all_min_row(A, i) for j in L: if is_col_max(A, i, j): return True return False A = [[0, -1, 1], [0, 0, 2], [-1, -2, 3]] assert saddle_point(A) A = [[3, 2], [1, 4]] assert not saddle_point(A) def saddle_point_list(tab): res = [] for i in range(len(A)): L = col_index_all_min_row(A, i) for j in L: if is_col_max(A, i, j): res.append((i, j)) return res A = [[ 0, - 1, 1], [ 0, 0, 2], [-1, -2, 3]] assert saddle_point_list(A) == [(1,0), (1,1)] A = [[3, 2], [1, 4]] assert saddle_point_list(A) == []
- Écrire une fonction
Écrire la définition d'une fonction
saddle_point_list
qui accepte un tableau en argument et retourne la liste de ses points selles. par exemple avecA = [[0,-1,1],[0,0,2],[-1,-2,3]]
l'appel
saddle_point_list(A)
doit retourner[(1,0), (1,1)]
.
2. Encore des boucles dans des tableaux
On appellera tableau (de dimension deux) toute liste de liste rectangulaire. On appelle sous-tableau une partie rectangulaire d'un tableau (c'est à dire constituée de lignes et de colonnes successives).
Écrire une fonction
a_une_ligne_strict_pos
qui accepte un tableau en entrée et renvoieTrue
s'il a une ligne dont tous les éléments sont strictement positifs etFalse
sinon.def a_une_ligne_strict_pos(tab): n, p = len(tab), len(tab[0]) for line in tab: line_strict_ops = True for elmt in line: if elmt <= 0: line_strict_ops = False if line_strict_ops: return True return False A = [[-1, 1], [1, 1]] assert a_une_ligne_strict_pos(A) A = [[0, 1], [1, 0]] assert not a_une_ligne_strict_pos(A) A = [[-1, 1], [1, -2]] assert not a_une_ligne_strict_pos(A)
Idem avec les colonnes: écrire une fonction
a_une_colonne_strict_pos
qui accepte un tableau en entrée et renvoieTrue
s'il a une colonne dont tous les éléments sont strictement positifs etFalse
sinon.def a_une_colonne_strict_pos(tab): n, p = len(tab), len(tab[0]) for j in range(p): col_strict_ops = True for i in range(n): if tab[i][j] <= 0: col_strict_ops = False if col_strict_ops: return True return False A = [[-1, 1], [1, 1]] assert a_une_colonne_strict_pos(A) A = [[0, 1], [1, 0]] assert not a_une_colonne_strict_pos(A) A = [[-1, 1], [1, -2]] assert not a_une_colonne_strict_pos(A)
Écrire une fonction
chaque_ligne_au_moins_un_strict_pos
qui accepte un tableau en entrée et renvoieTrue
si toutes les lignes ont au moins un élément strictement positif etFalse
sinondef chaque_ligne_au_moins_un_strict_pos(tab): for line in tab: un_elmt_strict_pos = False for elmt in line: if elmt > 0: un_elmt_strict_pos = True break if not un_elmt_strict_pos: return False return True A = [[-1, 1], [1, 1]] assert chaque_colonne_au_moins_un_strict_pos(A) A = [[0, 1], [1, 0]] assert chaque_colonne_au_moins_un_strict_pos(A) A = [[-1, -1], [1, -2]] assert not chaque_colonne_au_moins_un_strict_pos(A)
Écrire une fonction
chaque_colonne_au_moins_un_strict_pos
qui accepte un tableau en entrée et renvoieTrue
si toutes les colonnes ont au moins un élément strictement positif etFalse
sinondef chaque_colonne_au_moins_un_strict_pos(tab): n, p = len(tab), len(tab[0]) for j in range(p): un_elmt_strict_pos = False for i in range(n): if tab[i][j] > 0: un_elmt_strict_pos = True break if not un_elmt_strict_pos: return False return True A = [[-1, 1], [1, 1]] assert chaque_colonne_au_moins_un_strict_pos(A) A = [[0, 1], [1, 0]] assert chaque_colonne_au_moins_un_strict_pos(A) A = [[-1, -1], [1, -2]] assert not chaque_colonne_au_moins_un_strict_pos(A)
- Écrire une fonction
taille_max_sous_tab_strmt_pos
qui accepte un tableau en argument et retourne la taille (sous la forme d'un tuple(nb_lignes,nb_colonnes)
) d'un des sous-tableaux de taille maximal (ici comprendre: qui a le plus d'éléments) parmi ceux constitués uniquement de réels strictement positifs. Ainsi- avec
A=[[-1,1,3],[-2,5,-1],[-3,2,4]]
l'appeltaille_max_sous_tab_strmt_pos(A)
doit renvoyer(3,1)
. - avec
A=[[-1,1,3],[-2,5,1],[-3,2,-4]]
l'appeltaille_max_sous_tab_strmt_pos(A)
doit renvoyer(2,2)
.
- avec
3. Sous-chaînes et sous-chaînes extraites
- Écrire une fonction
nbr_max_car_succ_egaux
qui accepte une chaîne de caractères en argument et retourne un tuple donc le premier élément est un entier (la longueur de la plus grande sous-liste constante) et le second un caractère (le caract_re constituant cette sous-chaîne). Compléter et déboguer les fonctions itératives
est_sous_chaine_iter_sans_tranches
etest_sous_chaine_iter_avec_tranches
ci-dessous pour qu(elles acceptent deux arguments de typestr
et retournentTrue
si le second est une sous-chaîne du premier etFalse
sinon. Ainsi les appelsest_sous_chaine_iter_sans_tranches("abcd", "bc")
etest_sous_chaine_iter_avec_tranches("abcd", "bc")
doivent renvoyerTrue
alors que les appelsest_sous_chaine_iter_sans_tranches("abcd", "bd")
etest_sous_chaine_iter_avec_tranches("abcd", "bd")
doivent renvoyerFalse
. Rappelons que sis
(resp.L
) est une chaîne de caractères (resp. une liste) alorss[i:j]
renvoie la sous-chaîne (resp. la suos-liste) constituée des caractères (resp. des valeurs de la liste) d'indicek
vérifianti<=k<j
.def est_sous_chaine_iter_sans_tranches(??): for ind_str1 ni range(??): est_sous_chaine_ici = ?? for ind_str2 in range(??): if str1[??] != str2[??): est_sous_chaine_ici = ?? if est_sous_chaine_ici: retur ?? return ??
def est_sous_chaine_iter_avec_tranches(??): n1, n2 = len(str1), len(str2) for ind_str1 in range(??): if str1[??:??] == ?? return ?? return ??
def est_sous_chaine_iter_sans_tranches(str1, str2): for ind_str1 in range(len(str1)-len(str2)+1): est_sous_chaine_ici = True for ind_str2 in range(len(str2)): if str1[ind_str1+ind_str2] != str2[ind_str2]: est_sous_chaine_ici = False if est_sous_chaine_ici: return True return False def est_sous_chaine_iter_avec_tranches(str1, str2): n1, n2 = len(str1), len(str2) for ind_str1 in range(n1-n2+1): if str1[ind_str1:ind_str1+n2] == str2: return True return False str1, str2 = "acbabad", "cba" assert est_sous_chaine_iter_sans_tranches(str1, str2) assert est_sous_chaine_iter_avec_tranches(str1, str2) str1, str2 = "acbabad", "abd" assert not est_sous_chaine_iter_sans_tranches(str1, str2) assert not est_sous_chaine_iter_avec_tranches(str1, str2)
def est_sous_chaine_iter(str1, str2): for ind_str1 in range(len(str1)-len(str2)+1): est_sous_chaine_ici = True for ind_str2 in range(len(str2)): if str1[ind_str1+ind_str2] != str2[ind_str2]: est_sous_chaine_ici = False if est_sous_chaine_ici: return True return False str1, str2 = "acbabad", "cba" assert est_sous_chaine_iter(str1, str2) str1, str2 = "acbabad", "abd" assert not est_sous_chaine_iter(str1, str2)
On dira ici qu'une chaîne
str2
est une sous-chaîne extraite de la chaînestr1
si on peut obtenirstr2
en supprimant des caractères àstr1
. Écrire une fonction itérativeest_sous_chaine_extraite_iter
qui renvoieTrue
si si son second argument est une sous-chaîne extraite du premier etFalse
sinon. Ainsi- l'appel
est_sous_chaine_extraite_iter("acbabad", "acbbd")
doit renvoyerTrue
; - et l'appel
est_sous_chaine_extraite_iter("acbabad", "acbbb")
doit renvoyerFalse
.
def est_sous_chaine_extraite_iter(str1, str2): ind_str2 = 0 for ind_str1 in range(len(str1)): if ind_str2 == len(str2): return True if str1[ind_str1] == str2[ind_str2]: ind_str2 += 1 return ind_str2 == len(str2) str1, str2 = ("acbabad", "acbbd" assert est_sous_chaine_extraite_iter(str1, str2) str1, str2 = "acbabad", "acbbb" assert not est_sous_chaine_extraite_iter(str1, str2)
- l'appel
On dit d'un tableau
B
que c'est un sous-tableau deA
s'il forme un bloc rectangulaire deA
c'est à dire s'il s'obtient en ne gardant que des éléments situées dans certaines lignes et certaines colonnes successives deA
. Écrire une fonctionest_sous_tableau
qui fait vous savez quoi. Ici, mieux vaut utiliser les tranches (slices)!def est_sous_tableau_ici(A, B, i, j): nA, pA = len(A), len(A[0]) nB, pB = len(B), len(B[0]) assert 0<=i<nA and 0<=j<pA if i > nA-nB or j > pA-pB: return False for k in range(nB): if A[i+k][j:j+nB] != B[k]: return False return True A = [[1, 2 ,3, 4], [5, 6, 7, 8], [9,10,11,12]] B = [[ 6, 7], [10,11]] print(est_sous_tableau_ici(A, B, 1, 1))