Corrigé de la Composition d'Informatique

Jean-Berstel   Jean-Jacques Lévy

14 février 2001 -- 4h






Question 1


Question 2
  static int filsDe(int p, char c, Arbre a) {
    for (Liste x = a.succ[p]; x != null; x = x.suivant) 
      if (x.etiq == c) 
        return x.sommet;
    return -1;
  }
Question 3
  static int descendantDe(int p, String w, Arbre a) {
    for (int i = 0; i < w.length(); ++i) {
      p = filsDe (p, w.charAt(i), a);
      if (p == -1)
        return -1;
    }
    return p;
  }
Question 4
  static void inserer(String w, Arbre a) {
    int p = 0; 
    for (int i = 0; i < w.length(); ++i) {
      int q = filsDe (p, w.charAt(i), a);
      if (q == -1) {
        a.succ[p] = new Liste (w.charAt(i), a.n, a.succ[p]);
        p = a.n++;
      } else
        p = q;
    }
  }
Question 5
  static Arbre nouvelArbre(String[ ] x) {
    Arbre a = new Arbre();
    for (int i = 0; i < x.length; ++i)
      inserer (x[i], a);
    return a;
  }
Question 6

Question 7
  static void insererSuffixe(int i, String w, Arbre a) {
    int p = 0; 
    for ( ; i < w.length(); ++i) {
      int q = filsDe (p, w.charAt(i), a);
      if (q == -1) {
        a.succ[p] = new Liste (w.charAt(i), a.n, a.succ[p]);
        p = a.n++;
      } else
        p = q;
    }
    a.terminal[p] = true;
  }
  static Arbre nouvelArbreSuffixe(String w) {
    Arbre a = new Arbre();
    for (int i = 0; i <= w.length(); ++i)
      insererSuffixe (i, w, a);
    return a;
  }
Question 8
  static int[ ] nombreDeFacteurs(int N, Arbre a) {
    int[ ] cw = new int[N + 1];
    visiter (0, 0, cw, a);
    return cw;
  }

  static void visiter (int p, int profondeur, int[ ] cw, Arbre a) {
    ++ cw[profondeur];
    for (Liste x = a.succ[p]; x != null; x = x.suivant)
      visiter (x.sommet, profondeur+1, cw, a);
  }
Question 9a) La borne supérieure est atteinte quand tous les facteurs sont différents (par exemple quand toutes les lettres de w sont différentes). Alors F(w) = 1 + N + N-1 + ··· + 1 = 1 + N(N+1)/2. Inversement, la borne inférieure est atteinte quand tous les facteurs de même longueur sont égaux (par exemple quand toutes les lettres de w sont égales). Alors F(w) = N+1. En conclusion
N+1 £ F(w) £ 1 + N(N+1)/2

b) F(w) est le nombre de sommets de l'arbre suffixe. En dessinant l'arbre suffixe dans le plan cartésien en suivant l'axe des abcisses pour un arc étiqueté a et l'axe des ordonnées pour les arcs étiquetés b, on obtient F(w) = (n+1)2 (tous les points du carré de coté n).

Question 10 a) Un tel facteur est suffixe de w.

b) Chaque fois que xa est facteur pour une lettre a, le mot ya est aussi facteur.

c) On note Hw(k) l'ensemble des facteurs de longueur k de w. Alors Cw(k+1)=Cw(k) + dw(k) avec dw(k) = åxÎ Hw(k) d(x)-1. Pour que la somme dw(k) soit négative, il doit exister un facteur x0Î Hw(k) de degré 0. D'après (a), il est le seul de son espèce. Donc tous les autres facteurs de longueur k sont de degré 1 et dw(k)=-1.

d) Supposons l'assertion fausse, et soit w un mot de longueur minimale pour lequel l'implication est fausse, donc tel qu'il existe un entier k avec Cw(k)=Cw(k+1) et Cw(k+1) <Cw(k+2). Soit u le suffixe de longueur k de w, et posons w=w'a, où a est la dernière lettre de a.

(i) Si u n'est pas facteur de w', alors Cw'(k+i)=Cw(k+i)-1 pour i³ 0, car w' compte pour chaque longueur un facteur de moins que w, à savoir le suffixe de w de cette longueur. En vertu de la minimalité de w, on a Cw'(k+1)³ Cw'(k+2), donc par l'équation aussi Cw(k+1)³ Cw(k+2), contradiction.

(ii) Si u est facteur de w', alors tous les facteurs de w de longueur k sont de degré 1 exactement. Comme Cw(k+1) <Cw(k+2), il existe au moins un f acteur x de longueur k+1 de w de degré ³2. Mais alors, son suffixe de longueur k est aussi de degré ³2, contradiction.

Question 11Pour w = ababbb

Question 12Un arbre compacté a N+1 sommets terminaux. Si le mot ne contient pas deux lettres distinctes, son nombre de sommets est N+1. Dans le cas contraire, soit k le nombre de feuilles de l'arbre. On a k £ N parce que la racine est terminal sans être une feuille (mot non vide). Tous les sommets non terminaux sont de degré au moins 2. Il résulte des propriétés des arbres que le nombre de sommets de degré au moins 2 est au plus k-1, et la racine est parmi ces sommets. Les sommets non terminaux sont donc en nombre au plus k-2. Le nombre total de sommets est donc majoré par k-2 + N+1 £ 2N-1.

Question 13

  static int longueurMot (Arbre a) { return longueurMotR(a, 0); }

  static int longueurMotR (Arbre a, int p) {
    int r = 0;
    for (Liste x = a.succ[p]; x != null; x = x.suivant)
      r = Math.max (r, 1 + longueurMotR(a, x.sommet));
    return r;
  }
Question 14

  static ArbreA transformer (Arbre a) {
    ArbreA r = new ArbreA(); r.n = a.n;
    transformerR (r, 0, longueurMot(a), a);
    return r;
  }
  
  static void transformerR (ArbreA r, int p, int N, Arbre a) {
    for (Liste x = a.succ[p]; x != null; x = x.suivant) {
      int q = x.sommet;
      transformerR (r, q, N, a);
      ListeA qArc = r.succ[q];
      if (qArc == null)
        ajouterArcA(p, N - 1, N, q, r);
      else if (qArc.suivant == null && !r.terminal[q])
        ajouterArcA(p, qArc.debut - 1, qArc.afin, qArc.sommet, r);
      else
        ajouterArcA(p, qArc.debut - 1, qArc.debut, q, r);
      }
    r.terminal[p] = a.terminal[p];
   }

  static void ajouterArcA(int x, int deb, int afin, int y, ArbreA a) {
    a.succ[x] = new ListeA (deb, afin, y, a.succ[x]);
  }
Question 15

  static ArbreA epurer (ArbreA a) {
    ArbreA r = new ArbreA(); r.n = 0;
    epurerR (r, a, 0);
    return r;
  }

  static int epurerR (ArbreA r, ArbreA a, int p) {
    int p1 = r.n++; ListeA y = null;
    for (ListeA x = a.succ[p]; x != null; x = x.suivant) {
      int q = x.sommet; int q1 = epurerR (r, a, q);
      y = new ListeA(x.debut, x.afin, q1, y);
    }
    r.succ[p1] = y;
    r.terminal[p1] = a.terminal[p];
    return p1;
  }
Question 16

  static int lpc(int i, int j, int k, int l, String w) {
    int h = 0;
    while ( i < j && k < l && w.charAt(i)== w.charAt(k) ) {
      ++i; ++k; ++h;
    }
    return h;
  }
Question 17

  static void insererSuffixe(int i, String w, int p, ArbreA a) {
    ListeA arc;
    if ( i == w.length() || (arc = arcDe(p, w.charAt(i), w, a)) == null)
      ajouterSuffixeAuBout(p, i, w, a); 
    else {
      int h = lpc(arc.debut, arc.afin, i, w.length(), w);
      int q = arc.sommet;
      if (arc.debut + h < arc.afin) {
        int r = briserArc(p, arc, arc.debut + h, a);
        q = r;
      } 
      insererSuffixe(i + h, w, q, a);
    }
  }  

  static ListeA arcDe(int p, char c, String w, ArbreA a) {
    for (ListeA x = a.succ[p]; x != null; x = x.suivant) 
      if (w.charAt(x.debut) == c) 
        return x;
    return null;
  }

  static void ajouterSuffixeAuBout(int p, int i, String w, ArbreA a) {
    if (i == w.length()) 
      a.terminal[p] = true;
    else {
      int t = a.n++; a.terminal[t] = true;
      ajouterArcA(p, i, w.length(), t, a);
    }
  }

  static int briserArc(int p, ListeA arc, int k, ArbreA a) {
    int r = a.n++;
    ajouterArcA(r, k, arc.afin, arc.sommet, a);
    arc.sommet = r; arc.afin = k;
    return r;
  }
Question 18

  static ArbreA nouvelArbre(String w) {
    ArbreA a = new ArbreA();
    for (int i = 0; i <= w.length(); i++)
      insererSuffixe(i, w, 0, a);
    return a;
  }
Question 19En partant à partir de la racine, on avance dans le chemin vers p correspondant au facteur x en décidant sur la première lettre des étiquettes des arcs issus des sommets rencontrés. Le choix entre les arcs se fait séquentiellement et prend O(k) opérations. Au total, le calcul de p se fait en O(E × k).
Question 20Le facteur x=ay correspond au sommet p. Alors soit p est un noeud terminal, soit p est un sommet de degré au moins 2. Dans le premier cas, x est un suffixe, et donc également y. Il lui correspond donc bien un noeud terminal q. Dans le deuxième cas, il existe deux facteurs xz et xz' (zz' ¹ ). Comme x = ay, il existe aussi deux facteurs yz et yz', et donc le facteur y correspond à un noeud q de degré au moins supérieur à deux. Il correspond bien à un sommet dans l'arbre des préfixes.
Question 21

  static int[] lienSuffixe(String w, ArbreA a) {
    int[] ls = new int[a.n];
    for (int i = 0; i < ls.length; ++i) ls[i] = -1;
    faireLienSuffixe(0, ls, w, a);
    return ls;
  }

  static void faireLienSuffixe(int p, int[] ls, String w, ArbreA a) {
    if (p != 0 && ls[p] != -1)
      for (ListeA x = a.succ[p] ; x != null; x = x.suivant) {
        int q = x.sommet;
        int q1 = descendantDe(ls[p], x.debut, x.afin, w, a);
        faireLienSuffixe(q1, ls, w, a);
        ls[q] = q1;
        faireLienSuffixe(q, ls, w, a);
      }
  }

This document was translated from LATEX by HEVEA.