web-dev-qa-db-fra.com

comment trouver le nombre de sous-séquences distinctes d'une chaîne?

Voici un autre problème qui demande comment trouver le nombre de sous-séquences distinctes d'une chaîne?

Par exemple,

Contribution 
AAA 
ABCDEFG 
CODECRAFT 

Sortie 

128 
496 

Comment puis-je résoudre ce problème ?

36
user467871

C'est un problème de programmation dynamique classique.

Laisser:

dp[i] = number of distinct subsequences ending with a[i]
sum[i] = dp[1] + dp[2] + ... + dp[i]. So sum[n] will be your answer.
last[i] = last position of character i in the given string.

Une chaîne nulle a une sous-séquence, donc dp[0] = 1.

read a
n = strlen(a)
for i = 1 to n
  dp[i] = sum[i - 1] - sum[last[a[i]] - 1]
  sum[i] = sum[i - 1] + dp[i]
  last[a[i]] = i

return sum[n]

Explication

dp[i] = sum[i - 1] - sum[last[a[i]] - 1]

Initialement, nous supposons que nous pouvons ajouter a[i] à toutes les sous-séquences se terminant par les caractères précédents, mais cela pourrait violer la condition selon laquelle les sous-séquences comptées doivent être distinctes. Rappelez-vous que last[a[i]] nous donne la dernière position sur laquelle a[i] est apparu jusqu'à maintenant. Les seules sous-séquences que nous surestimons sont celles auxquelles le précédent a[i] a été ajouté. Nous soustrayons donc ces dernières.

sum[i] = sum[i - 1] + dp[i]
last[a[i]] = i

Mettez à jour ces valeurs selon leur définition.

Si votre indexation commence à 0, utilisez a[i - 1] partout où j'ai utilisé a[i]. Pensez également à envelopper vos calculs dans une fonction mod si vous souhaitez soumettre du code. Ceci devrait être implémenté comme ceci:

mod(x) = (x % m + m) % m

Afin de gérer correctement les valeurs négatives dans certains langages (tels que C/C++).

58
IVlad

Il existe une solution plus facile à ce problème.

L'idée est la suivante: si tous les caractères de la chaîne sont distincts, le nombre total de sous-séquences est égal à 2^n.. Maintenant, si nous trouvons un caractère déjà présent, nous devrions considérer sa dernière occurrence uniquement (sinon la séquence ne sera pas distincte). Nous devons donc soustraire le nombre de sous-séquences en raison de son occurrence précédente.

Ma mise en oeuvre est la suivante:

read s
dp[0] = 1
len = strlen(s)
last[s.length()] = {-1} //declaring `last` array with same as length of string `s` and all elements initialized with -1.

for (i = 1; i <= len; i++) 
{
    dp[i] = (dp[i - 1] * 2)
    if (last[s[i]] > 0) dp[i] = (dp[i] - dp[last[s[i]] - 1])
    last[s[i]] = i
}
30
Mostafiz Rahman

Voici monCODE:

#include<iostream>
typedef long long ll;

ll fun(std::string s,ll visited[256],ll n,ll L[]){  

    ll ans=0;
    if(n<0){
        return 1;
    }
    //std::cout<<s.substr(0,n+1)<<" "<<n<<endl;

    ans=fun(s,visited,n-1,L);
    L[n]=ans;
    ans=ans*2;
    if(visited[int(s[n])]>=0){
        ans -= L[visited[int(s[n])]];
    }
    visited[int(s[n])]=n;

    return ans;

}
int main(){

    std::string s;
    std::cin>>s;
    ll n=s.length();

    ll visited[256];
    ll L[n];
    memset(visited,-1,sizeof(visited));
    memset(L,-1,sizeof(L));

    std::cout<<fun(s,visited,n-1,L);

    return 0;
}

Explication

Je numérise à partir du dos d'une chaîne, c'est-à-dire du dernier élément au premier et envoie donc les premiers caractères n-1 pour une analyse plus poussée dans la récursivité.

Une fois n==-1 or n<0(both are same), j'atteins la chaîne vide et renvoie 1 car non. des sous-séquences d'une chaîne vide vaut 1.

Ainsi, en revenant de la récursion, nous savons que l'ajout du caractère non dupliqué actuel à la chaîne précédente double le n °. de sous-séquences. Le doublage se produit car je peux maintenant ajouter ce caractère à la fin de toutes les sous-séquences précédentes. Donc, with et without, ce caractère représente le double de toutes les sous-séquences précédentes.

En supposant que le caractère actuel ne soit pas un doublon, je multiplie le no précédent. de sous-séquences avec 2.

Après le non total des sous-séquences des premiers caractères n-1 ont été calculées, nous les doublons pour les premiers caractères n.

Mais supposons que le caractère actuellement rencontré (nième caractère) ait déjà été présent dans les premiers n-1 caractères précédents (c'est-à-dire trouvé dans la chaîne s [0 ... n-1] (Remarque: s [n] est le caractère actuel). )), alors nous devons soustraire ces non. de sous-séquences possibles allant de (excluant) cette partie de s lors de la dernière fois où ce caractère courant a été rencontré et qui a déjà été calculée et stockée dans L ['ce caractère particulier'].

c'est-à-dire - BACA - pour la chaîne donnée, le 4ème A a déjà été rencontré auparavant (en revenant de la récursion, nous rencontrons d'abord B, puis A, puis C et enfin A) et nous déduisons donc le non. des sous-séquences calculées jusqu'à (excluant) la 2e A (qui est 2 (car le nombre de sous-séquences précédant A est égal à 2)). 

Donc, chaque fois que nous avons calculé le non. des sous-séquences pour les premiers n-1 caractères, nous les stockons dans le tableau L.

Remarque : L [k] enregistre le no. des sous-séquences avant le kème indice.

J'ai utilisé le tableau visité pour vérifier si le personnage auquel je suis présent a déjà été scanné ou non. 

Lorsque je rencontre le caractère actuel, je mets à jour le tableau visité avec la position de la position actuelle sous la forme n. Cela doit être fait car nous devons exclure les séquences en double.

Remarque : visited[] est initialisé avec tout -1 car la position de tout caractère de la chaîne s est non négative (indexation basée sur 0). 

Résumé :

How do you arrive at the number of duplicates? Let's say the last occurrence of current character at i, was at j'th position. Then, we will have duplicate subsequences: consider starting with i'th character and then all subsequences possible from [0,j-1] vs. starting at j'th character and then all subsequences possible from [0,j-1]. So, to eliminate this, you subtract the number of subsequences possible from upto (excluding) j with L[0]=1 mean that upto(excluding 0), no. of subseq are 1(empty string has 1 subsequence).

0
jay