Aller au contenu principal

LeetCode 2

Quentin Fortier
Professeur d'informatique

Exercice à faire en C sur LeetCode, au plus tard pour samedi prochain : https://leetcode.com/problems/merge-two-sorted-lists

Indice

On pourra écrire une fonction récursive.

Si vous avez terminé l'exercice, vous pouvez faire ce prolongement (plus difficile) : https://leetcode.com/problems/merge-k-sorted-lists

Indice

Réutiliser la fonction précédente pour fusionner deux listes.
L'idéal est de résoudre ce problème en O(n log (k)) où n est la somme des tailles des listes et k le nombre de listes.

Solution

Solution en O(nlog(k)) avec une approche diviser pour régner (où n = somme des tailles des listes et k = nombre de listes) :

  • l1 = fusionner récursivement les k/2 premières listes
  • l2 = fusionner récursivement les k/2 dernières listes
  • retourner la fusion (avec mergeTwoLists) de l1 et l2

Chaque fusion s'effectue en O(n) et il y a log(k) fusions, d'où la complexité en O(nlog(k))

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
if (list1 == NULL) return list2;
if (list2 == NULL) return list1;
if (list1->val <= list2->val) {
list1->next = mergeTwoLists(list1->next, list2);
return list1;
}
if (list1->val > list2->val) {
list2->next = mergeTwoLists(list1, list2->next);
return list2;
}
return NULL;
}

struct ListNode* merge(struct ListNode** lists, int i, int j) {
if(i + 1 == j) return lists[i];
if(i == j) return NULL;

int m = (i + j)/2;
return mergeTwoLists(merge(lists, i, m), merge(lists, m, j));
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
return merge(lists, 0, listsSize);
}

Colle 1 : Langages, automates et grammaires

Quentin Fortier
Professeur d'informatique

Voici la liste des compétences et connaissances à avoir pour votre première colle. La colle est constituée d'un ou plusieurs exercices.

Langages :

  • Définitions et opérations sur les mots et langages
  • Montrer l'égalité de deux langages (double inclusion...)
  • Montrer une propriété par récurrence sur des mots
  • Connaître la définition de langage régulier
  • Montrer qu'un langage est régulier (éventuellement en passant par une expression régulière)
  • Connaître la syntaxe des expressions régulières
  • Montrer une propriété sur les langages réguliers (ou expressions régulières) par induction structurelle
  • Écrire un programme OCaml pour manipuler une expression régulière

Automates :

  • Définitions
  • Écrire un programme OCaml pour manipuler un automate
  • Montrer qu'un langage est reconnaissable
  • Trouver le langage reconnu par un automate
  • Compléter un automate
  • Algorithme de déterminisation et automate des parties
  • Stabilité des langages reconnaissables par complémentaire, intersection, union, différence. Automate produit.
  • États accessibles et co-accessibles. Automate émondé. Tout automate est équivalent à un automate émondé.
  • Lemme de l'étoile, avec démonstration et application pour montrer qu'un langage n'est pas reconnaissable.

Théorème de Kleene :

  • Langage local, expression régulière linéaire.
  • Algorithme de Berry-Sethi pour construire un automate (de Glushkov) à partir d'une expression régulière.
  • ε-transitions. Tout automate avec des ε-transitions est équivalent à un automate sans ε-transition.
  • Automate de Thompson (construit récursivement) à partir d'une expression régulière.
  • Méthode d'élimination des états pour obtenir une expression régulière à partir d'un automate.
  • Théorème de Kleene et conséquences.

Grammaires :

  • Grammaire non-contextuelle (algébrique, hors-contexte).
  • Dérivation.
  • Langage engendré. Savoir démontrer par récurrence (sur la longueur du mot ou de la dérivation) que le langage engendré par G est bien ce qu'on souhaite.
  • Les langages réguliers sont algébriques.
  • Arbre de dérivation.
  • Grammaire ambigüe. Dérivation gauche. Savoir montrer qu'une grammaire est ambigüe.
  • Analyse syntaxique : exemple.

LeetCode 1

Quentin Fortier
Professeur d'informatique

Voici le premier exercice à faire en C sur LeetCode, au plus tard pour dimanche prochain (15 septembre) : https://leetcode.com/problems/longest-substring-without-repeating-characters
Une vidéo explicative pour utiliser LeetCode : https://youtu.be/q5dEFWMO8-o
Vous pouvez me demander de l'aide par mail.

Solution
// 1ere solution : O(n^3) en regardant, pour chaque sous-chaîne, si elle contient un doublon
int lengthOfLongestSubstring(char* s) {
int max = 0;
for(int i = 0; i < strlen(s); i++) {
int j = i + 1;
int b = 0;
while(j < strlen(s)) {
for(int k = i; k < j; k++) {
if(s[k] == s[j])
b = 1;
}
if(b) break;
j++;
}
if(j - i > max)
max = j - i;
}
return max;
}

// 2eme solution : O(n^2) en conservant un tableau count pour savoir si un caractère est déjà présent dans la sous-chaîne
// on utilise un tableau de 256 éléments pour les caractères ASCII
int lengthOfLongestSubstring(char* s) {
int max = 0;
int n = strlen(s);
for(int i = 0; i < n; i++) {
int j = i;
int count[256] = {0};
while(j < n && count[s[j]] == 0) {
count[s[j]] = 1;
j++;
}
if(j - i > max)
max = j - i;
}
return max;
}

Codespace GitHub

Quentin Fortier
Professeur d'informatique

Pour pouvoir utiliser un environnement de développement en ligne avec Visual Code, OCaml, utop, gcc :

  • S'incrire sur GitHub (Sign Up).
  • Aller sur https://github.com/mpi-lamartin/environnement et cliquer sur le bouton Code puis "Create codespace on main".
  • Vous pouvez retrouver votre codespace en cliquant sur le menu en haut à gauche puis "Codespaces".
  • Les fichiers sont normalement sauvegardés en ligne... Vous pouvez quand même télécharger (dans "fichier") des fichiers importants pour être sûr de ne pas les perdre.
  • Par défaut vous avez le droit à 120h/mois d'utilisation, ce qui devrait être suffisant. Vous pouvez demander un compte étudiant pour avoir 180h/mois : https://github.com/education/students.

Vidéo explicative