Titre: Algo du soir, Bonsoir ! Posté par: BAAL le 26 Février 2017 à 22:55:34 Dans la même veine que le fil de discussion “Enigme du soir, Bonsoir !”, on peut ici proposer des problèmes de code/algo qui ne sont pas facilement transférables en challenge officiel. Soit car la solution se trouve facilement sur Google, soit parce qu’on peut toujours réussir avec une solution non-optimale si on laisse le code tourner assez longtemps, ou pour d’autres raisons...
Je commence avec un problème pas trop dur: Codez une fonction qui prend comme argument un array de int, positifs et négatifs, et qui retourne la somme de la sous-séquence qui donne la plus grande somme. Par exemple: input = [3, -10, 3, -2, 5, -7] output = 6 (somme de [3, -2, 5]) Titre: Re : Algo du soir, Bonsoir ! Posté par: pixis le 27 Février 2017 à 15:20:45 Du coup le challenge, c'est de trouver la fonction la plus optimale, j'imagine :)
Parce que sinon, je te bf toutes les solutions /me siffle Non mais j'ai une petite idée en tête un peu tordue. Je pense pas qu'elle soit optimale mais je suis curieux de savoir si j'arrive à la mettre en place "simplement". I'll let you know ! Titre: Re : Algo du soir, Bonsoir ! Posté par: the lsd le 27 Février 2017 à 17:07:23 Question bête, optimale, là, on l'entend dans quel sens ?
Niveau timing, utilisation ressources, taille/compléxité du code, autre ? Enjoy The lsd Titre: Re : Algo du soir, Bonsoir ! Posté par: pixis le 27 Février 2017 à 17:27:24 Je pensais à complexité en temps, mais effectivement, il faudrait aussi optimiser la complexité en mémoire.
Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 27 Février 2017 à 17:31:13 On entend complexité espace/temps asymptotique. Temps la plupart du temps.
Dans le cas de la question ci-dessus, un algo "bête" trouve la réponse en temps O(n^2), mais on peut faire mieux! Titre: Re : Algo du soir, Bonsoir ! Posté par: harvey le 27 Février 2017 à 18:19:51 En O(n):
Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 28 Février 2017 à 04:18:11 J’ai fait ça un peu différemment, ton code est plus compact, mais il m’a l’air bon! J’aime bien les problèmes où on passe de O(n^2) à O(n) en réfléchissant un peu :).
Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 05 Mars 2017 à 02:26:08 Un peu plus compliqué cette fois-ci: On cherche une fonction qui reçoit un array de nombres entiers positifs et retourne le nombre qu’on retrouve le plus de fois dans l’array, s’il y est au moins 50% du temps. Sinon on retourne -1.
Exemple: input = [1, 5, 3, 2, 3, 10, 3, 3, 3] output = 3 input = [1, 5, 3, 2, 3, 10, 3, 3, 4] output = -1 La solution doit être en temps O(n) et espace O(1). Titre: Re : Algo du soir, Bonsoir ! Posté par: harvey le 06 Mars 2017 à 00:54:02 L'énoncé ne précise pas que faire quand deux éléments forment 50% du tableau chacun.
Je suppose qu'on doit retourner -1. Je pense avoir une solution en O(n) en moyenne. La taille du tableau est N. Initialiser les bornes bmin = 0, bmax = infini Boucle: -choisir un élément du tableau au hasard (= p) tel que bmin < p < bmax -compter le nombre d'éléments x (bmin < x < bmax) supérieurs, égaux et inférieurs à p -si aucun de ces ensembles n'est de taille supérieure ou égale à N/2: retourner -1 -si l'ensemble d'éléments égaux à p est de taille >= N/2: -si partage 50/50, retourner -1, sinon retourner p -sinon, poser bmin = p (si l'ensemble supérieur à p est le plus gros), ou bmax = p (si l'ensemble inférieur est le plus gros), et boucler Il y a 7 variables (mémoire constante). Le temps est N^2 dans le pire des cas (si chaque itération n'élimine qu'un seul élément), mais N en général. Le nombre d'itérations moyen ne dépend pas des paramètres (c'est proche de 3 quand tous les éléments sont différents). Si, comme je l'ai lu quelque part, il existe un algo pour trouver la médiane en O(n) dans le pire des cas, il est certainement possible d'améliorer. Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 06 Mars 2017 à 18:31:16 J'aime bien ton idée, mais on peut faire mieux: O(n) dans le pire des cas!
Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 12 Mars 2017 à 23:43:44 Rien à voir avec la médiane d'ailleurs.
Cette question n'est vraiment pas si difficile, ça ne devrait pas prendre plus de quelques minutes. Titre: Re : Algo du soir, Bonsoir ! Posté par: pixis le 13 Mars 2017 à 09:21:48 Hello,
J'ai cherché une solution, mais ta condition "s’il y est au moins 50% du temps" me bloque. J'ai trouvé du O(n) pour le cas de majorité absolue, mais lorsque j'arrive à des cas où la majorité est tout pile 50%, je me retrouve avec le dernier élément qui sort de mon algo au lieu de l'élément présent à 50%, et je ne vois pas comment le contourner. Je pense que je dois trouver une autre manière de faire parce que là je suis un peu dans une impasse. Je continue de réfléchir du coup avant de poster ma solution. Titre: Re : Re : Algo du soir, Bonsoir ! Posté par: harvey le 22 Mars 2017 à 12:35:38 J'ai cherché une solution, mais ta condition "s’il y est au moins 50% du temps" me bloque. J'ai trouvé du O(n) pour le cas de majorité absolue, mais lorsque j'arrive à des cas où la majorité est tout pile 50%, je me retrouve avec le dernier élément qui sort de mon algo au lieu de l'élément présent à 50%, et je ne vois pas comment le contourner. Ton algorithme fonctionne dans tous les cas si la longueur du tableau est impaire. Dans le cas où elle est paire, il suffirait de compter le nombre d'occurrences du premier élément, et s'il n'est pas majoritaire d'appliquer l'algo à partir du second. Ça reste dans la borne O(n).Titre: Re : Algo du soir, Bonsoir ! Posté par: Alkanor le 22 Mars 2017 à 15:36:35 En O(n log(n)) temps et O(1) espace on peut se contenter de trier le tableau et de compter ensuite.
Edit : d'ailleurs par rapport à la complexité spatiale, est-ce qu'on considère que modifier le tableau initial (chaque case) génère une complexité spatiale O(n) ou bien on reste en O(1) ? (dans le premier cas d'ailleurs le tri serait alors en O(n) spatialement) Edit2 : je pense avoir trouvé quelque chose qui marche : on crée une sorte d'échelle sur l'élément majoritaire : on parcourt le tableau une fois, pour chaque élément, soit c'est le même élément que celui qui est associé à l'échelle actuellement et on monte d'une case, soit ça n'est pas le cas et on descend d'une case. Si l'échelle est vide (comme au début de l'algo par exemple), on change l'élément associé à l'échelle par l'élément actuel. A la fin on obtient un élément qui correspond au seul majoritaire possible. Mais ça n'est pas sûr que c'en soit effectivement un. Il suffit de refaire un parcours du tableau en comptant l'élément trouvé à la fin et en vérifiant qu'il est bien présent dans une quantité supérieure à la moitié de la taille du tableau. Titre: Re : Algo du soir, Bonsoir ! Posté par: pixis le 22 Mars 2017 à 16:26:02 Merci Harvey. Mon code est sale mais je crois qu'il marche et qu'il est O(n) en temps si je ne me trompe pas. En revanche il esy O(n2) en espace il me semble ... Je dois pouvoir le faire sans récursion
Code: (python) def maj(l, next_n=-1, count=0): edit : Ah bah oui je peux le faire sans récursion et là c'est O(n) temps et 0(n) espace (sauf que je pense pas avoir compris la complexité espace, ya forcément besoin de O(n) pour une liste de longueur n non ?) Code: (python) def maj(l): edit 2 : Ah dans ma première version j'étais aussi 0(n2) à cause de ma récursion pour les listes paires. Il fallait que je sorte la comparaison de la fonction, c'est tout. Titre: Re : Algo du soir, Bonsoir ! Posté par: harvey le 22 Mars 2017 à 23:40:01 Joli, pixis. Effectivement, ça devient simple quand on se rend compte qu'on n'introduit pas de faux négatif en retirant un sous-ensemble sans élément strictement majoritaire. Et qu'il y a au plus deux éléments à recompter à la fin dans le pire des cas (de la manière dont j'interprète l'énoncé, en tout cas).
On peut aussi éviter le test en début de fonction (ça ne change pas grand chose): Code: #encoding=utf8 Titre: Re : Algo du soir, Bonsoir ! Posté par: BAAL le 23 Mars 2017 à 04:42:06 Bien joué à vous trois! Alkanor a donné la bonne approche en premier, mais sans code, et on dirait que pixis avait trouvé avant mais sans finaliser proprement. Enfin bref... C’était bien ça!
Voici l’algo en question, avec une belle illustration: https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm Pour répondre à vos questions sur la complexité spatiale: >>>> Edit : d'ailleurs par rapport à la complexité spatiale, est-ce qu'on considère que modifier le tableau initial (chaque case) génère une complexité spatiale O(n) ou bien on reste en O(1) ? (dans le premier cas d'ailleurs le tri serait alors en O(n) spatialement) Ça dépend: s’il est permis de modifier le tableau donné, vu que tu peux le trier sur place (e.g. quicksort), la complexité spatiale est O(1). Mais dans ce problème je crois qu’il est plus rigoureux de supposer que le tableau donné ne peux être modifié, auquel cas tu dois créer un autre tableau pour sauver la version triée: Ça donne donc une complexité O(N). >>>> edit : Ah bah oui je peux le faire sans récursion et là c'est O(n) temps et 0(n) espace (sauf que je pense pas avoir compris la complexité espace, ya forcément besoin de O(n) pour une liste de longueur n non ?) Non, la complexité de ton algo dépend de l’espace additionel que tu génères, le tableau donné ne compte pas. Si à chaque itération tu ne fais que sauver une variable, c’est O(1). Si par contre tu crées un tableau de N éléments, c’est O(N), mais il n’y en a pas besoin ici comme tu as bien vu. Si O(N) espace était permis, je crois que la solution la plus évidente serait d’avoir un compteur pour chaque nombre qu’on lit, puis de passer à travers tous les compteurs et de voir lequel est le plus grand. Titre: Re : Algo du soir, Bonsoir ! Posté par: pixis le 23 Mars 2017 à 07:55:20 Ah bah l'algo a le même soucis que moi, ça ne marche que pour des majorités strictes
Citation Initialize an element m and a counter i with i = 0 For each element x of the input sequence: If i = 0, then assign m = x and i = 1 else if m = x, then assign i = i + 1 else assign i = i − 1 Return m input = [2,3,4,2] => On va avoir Cycle 1 : m = 2 et i = 1 Cycle 2 : m= 2 et i = 0 Cycle 3 : m = 4 et i = 1 Cycle 4 : m = 4 et i = 0 Ca va donc retourner 4 et voir que ce n'est pas majoritaire, donc ça donnera -1. Mais avec la technique d'harvey, on s'en sort :) |