Recherche dans une grille triée

On considère un tableau bidimensionnel d'éléments distincts, dont chaque ligne et chaque colonne est triée dans l'ordre croissant. On souhaite savoir si un élément cible est présent dans ce tableau.

Exemple

Cette grille possède bien chaque ligne et chaque colonne triées.

\[ \begin{matrix} 11 & 33 & \mathbf{42} & 63 \\ 20 & 52 & 67 & 80 \\ 25 & 61 & 88 & 95 \\ \end{matrix} \]
  • \(42\) est présente à la ligne 0, colonne 2.
  • \(24\) est absent.

Fonctions à utliser

La grille utilisée ici ne sera pas une liste Python et vous n'avez pas un accès direct aux données qu'elle contient.

En revanche, vous avez à votre disposition trois fonctions (déjà chargées en mémoire) telles que :

  1. nb_lignes(grille) renvoie le nombre \(n\) de lignes de la grille.
  2. nb_colonnes(grille) renvoie le nombre \(m\) de colonnes de la grille.
  3. donne_valeur(grille, i, j) renvoie la valeur de grille à la ligne i et la colonne j.

On vous demande d'écrire une fonction telle que recherche(cible, grille) renvoie None si la cible est absente de grille, sinon le tuple (i, j) tel que donne_valeur(grille, i, j) est égal à la cible. On définit le coût de la recherche comme le nombre d'appels à la fonction donne_valeur.

On rappelle que la grille possède la propriété que chaque ligne et chaque colonne sont triées.

Attention

Certaines des grilles utilisées dans les tests contiennent beaucoup de valeurs. Une méthode de coût linéaire sera inefficace face à celles-ci.

On limite donc le nombre de lectures dans chaque grille à 2000. Passée cette valeur maximale, tout nouvel accès provoquera une erreur.

Dans les tests, la fonction nb_acces permet de connaitre le nombre de lectures de la grille.

Exemples

Avec la grille définie comme dans le premier test public, on a

🐍 Console Python
>>> recherche(42, grille)
(0, 2)
>>> recherche(24, grille) is None
True

Efficacité

On attend une recherche efficace.

Une écriture itérative pourra être plus simple qu'une écriture récursive. Les deux sont possibles.

Indice

En partant d'un des coins supérieur droit ou inférieur gauche :

  • soit on trouve la cible,
  • soit on peut éliminer une ligne entière ou une colonne entière

Dans le pire des cas, en \(n+m\) tentatives, on a éliminé toutes les lignes et toutes les colonnes.

Après avoir éliminé une ligne ou une colonne, on se retrouve à chercher une cible dans une grille rectangulaire, ainsi on se retrouve dans une situation similaire à la précédente.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 10/10
.128013bûeqn×,49vi+3mo5_txR;PhkjlpwNf(: cg.a=ry0S6I-u/72)s18d050$0d0s0L0l0A0Z0H0I0A0L0Z0Z0M010s0l0B010406050Z0U0o0o0L0N0O040Q0p0A0U0`0p0f0H020L0o0B0v0H0u0d140N0e0U0d0Z050V111315170 0B04051C1v1F0V1C0 0$0l0k0/0;0?0^0x0l0J0x0A1T0x0s0}050*0b0A0d1O0=0@011S1U1W1U0s1$1(1!0s0N1D0s0x0/1a0Z0B0L0f0^0X011*1Q010E0,0d0f1i0d1!2022271,2a1(2d0o2f040a0H0w0N0p0B0p0Z0l1d1f0(1~0N0N0d0I2A1v2h0f1D0V1|2M1_1{1`1#0$2j0^1W0f2c2x1!1L1N0:1+2W0l2Y0f0p2$1!0B2F1D2K2M2@10211f2(282-0N140A0}0H0!2J2{0~2`2i2}1,2 31330X3622382K2V013d0L32040H0n3h2L0 3k3b0^3n3p0H0i3t3j2{3l3z330q3D3v3F3x3m0p303o330R3K392|1P3c3P3e3q0W3U3w3X3y3Z3R3q0#3%3M3)3O3Q3A0j3/3a3;3H040!0P3_3W2)3=3!0!351w373L3`423|0!3g473i49412~3+3p0!3s4f3u3V3G4k0}0!3C4o2M2;0d2M2$2P0$1{2U3N0I2.2p0%1M1D4y2?373D054H0(4O4a280y0}0(0E4Q3(420C334#3:4b0E0}2F0I0x0d0N4:0d4*4V1,0|040F4_4i3c0}0I0l1%4^4w4q3N4|0h3D0H583{0}0J0N0,1(4 3l4|0Y0G3K0H5r5d4$2~0}0f5c5e420p0}0M5y5u51040f0b0r1:2Y1u575F0^4|4~5O4+5v045h5j562_5P015n5q5s5z5V0o5E5U1,5B045D4w5t5.3y5w5J4H0A1e5M5l590}5S5!5^3m5g5i0A5k5T4`5Q0}0Y5(5r5*5G0l5-6c015:5=2@5@6m0o0l0}3 4w065s6r505_040z6l6B6n5C6F3G0}5,5?6i0^5:0T6J3N6t4t6g6A3l4X040C1S6a6q6O5$62605f046k6N5#5:020A0s0v6S6-5x6b6G5%6:650p4(04220$6`425R6,4b0}6E706m6=0J6^6p376X6T6u046w646m5n5p6x6z6z6)0f0}0t77286o7B5G0$5~0d0r0k3o0d0U0N7a28796}6K5W686%4P5#5a7E6C6/7q6~0}5b7e6G7y6D7P4{6e6W7w5#6Z0l4!7+7T7A7{3N7g6^7!660453557/6d047t2@6y7v8d7x7c826Q7j3i7l3;6U3}7=5)7@0}0d1W7`6(5#7-7}8w710}6?817~6-857W3i6)4|8a488d8e8x0}7$7k6)5:0m8j2L8l428n468b8O8Z4W8s0-5Z7X658L8p8P656Z2F0s7N6|8A7r6+7S3N7-8S8J7Y7)827-7d7%5m7;7u8q8?4.0)8`820y0I0}0D1e8-4g1v4S4z1G2=1v4B1v0s4D9x2S2N0L554A4L1B4U6G2F0o0r0E0L0y7I0x0n0}1n1p1r1t0H8M8J1I381C0S0A0H0d0t0l0Z0s1)0B1b2y7M0N0.3o0J3P2z0x2o0.2w7N0H0U2Y0H5X691)2C6)159}149/0t0}090F0f096f5?5L9X0)8)1,ac1|ae9+ah0F0oal5c5|7H0Z0h0H7G0f0s0H1eaG7H0H1(1~0caJ101_1e0J040$220.aP0B0l2FaG9X0I0=2JaU0faW9*9.9Y1G381a381W041n4@4?4;9*0t0x0L0U9.1Ma9aZ0/b39W0/0=0daFaHaJaP4HaRa;aS5#at9~0Lafax0f0gazam2@0K1va{0 a{a}4;a a90l4:0p0s0p6tbc110Nba0LbcaoaMaIaO1)bkaJ1tb!0f0ka%aLab5iaubraw04aiak5}0Jay0YaA4wbz0VbB05bD2GbF4@aGbI0xbKbM0lbOa24:bS1s1~5}0fa5bhbXaQb!a=2cb(2u1fb+adb.agb:ay09b?ajb_bx37b|b~c0a~c30d0E2aa+0IbfbVbibY0pblb#ar0^bpavcvai0o0makcC3icE0l380Va_0 0V0(0*0,0Z04.