Mon problème est de trouver la séquence répétitive de caractères dans le tableau donné. simplement, pour identifier le motif dans lequel les caractères apparaissent.
.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
1: | J | A | M | E | S | O | N | J | A | M | E | S | O | N |
'---'---'---'---'---'---'---'---'---'---'---'---'---'---'
.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
2: | R | O | N | R | O | N | R | O | N | R | O | N | R | O | N |
'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'
.---.---.---.---.---.---.---.---.---.---.---.---.
3: | S | H | A | M | I | L | S | H | A | M | I | L |
'---'---'---'---'---'---'---'---'---'---'---'---'
.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.---.
4: | C | A | R | P | E | N | T | E | R | C | A | R | P | E | N | T | E | R |
'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'---'
Compte tenu des données précédentes, le résultat devrait être:
"JAMESON"
"RON"
"SHAMIL"
"CARPENTER"
Pour vos exemples, ma première approche serait de
C
)CARPENTER
)Bien sûr, cela ne fonctionne que pour un sous-ensemble très limité de tableaux possibles, où le même mot est répété maintes et maintes fois, en commençant par le début, sans caractères parasites entre les deux, et son premier caractère n'est pas répété dans le mot. Mais tous vos exemples entrent dans cette catégorie - et je préfère la solution la plus simple qui puisse éventuellement fonctionner :-)
Si le mot répété contient plusieurs fois le premier caractère (par exemple, CACTUS
), l'algorithme peut être étendu pour rechercher également les occurrences ultérieures de ce caractère, et pas seulement le premier (de sorte qu'il trouve le mot entier répété, et pas seulement une sous-chaîne de caractères). il).
Notez que cet algorithme étendu donnerait un résultat différent pour votre deuxième exemple, à savoir RONRON
au lieu de RON
.
La langue dans les joues O(NlogN) solution
Effectuer une FFT sur votre chaîne (traiter les caractères comme des valeurs numériques). Chaque pic du graphique obtenu correspond à une périodicité de sous-chaîne.
En Python, vous pouvez utiliser les regex comme suit:
def recurrence(text):
import re
for i in range(1, len(text)/2 + 1):
m = re.match(r'^(.{%d})\1+$'%i, text)
if m: return m.group(1)
recurrence('abcabc') # Returns 'abc'
Je ne sais pas comment cela se traduirait en Java ou en C. (C'est l'une des raisons pour lesquelles j'aime Python, je suppose. :-)
Commencez par écrire une méthode qui trouve la sous-chaîne répétitive sub
dans la chaîne de conteneur, comme indiqué ci-dessous.
boolean findSubRepeating(String sub, String container);
Continuez maintenant à appeler cette méthode avec l'augmentation de la sous-chaîne dans le conteneur. Commencez par essayer une sous-chaîne de 1 caractère, puis 2 caractères, etc. jusqu'à container.length/2
.
La première idée qui me vient à l’esprit est d’essayer toutes les séquences répétitives de longueurs divisant la longueur (S) = N. Il existe un maximum de N/2 de telles longueurs, il en résulte un algorithme O (N ^ 2).
Mais je suis sûr que cela peut être amélioré ...
Pseudocode
len = str.length
for (i in 1..len) {
if (len%i==0) {
if (str==str.substr(0,i).repeat(len/i)) {
return str.substr(0,i)
}
}
}
Remarque: par souci de concision, j'invente une méthode de "répétition" pour les chaînes, qui ne fait pas partie de la chaîne de Java; "abc" .repeat (2) = "abcabc"
Utilisation de C++:
//Splits the string into the fragments of given size
//Returns the set of of splitted strings avaialble
set<string> split(string s, int frag)
{
set<string> uni;
int len = s.length();
for(int i = 0; i < len; i+= frag)
{
uni.insert(s.substr(i, frag));
}
return uni;
}
int main()
{
string out;
string s = "carpentercarpenter";
int len = s.length();
//Optimistic approach..hope there are only 2 repeated strings
//If that fails, then try to break the strings with lesser number of
//characters
for(int i = len/2; i>1;--i)
{
set<string> uni = split(s,i);
if(uni.size() == 1)
{
out = *uni.begin();
break;
}
}
cout<<out;
return 0;
}
Mettez tous vos personnages dans un tableau e.x. une[]
i=0; j=0;
for( 0 < i < count )
{
if (a[i] == a[i+j+1])
{++i;}
else
{++j;i=0;}
}
Ensuite, le rapport de (i/j) = nombre de répétitions dans votre tableau. Vous devez faire attention aux limites de i
et j
, mais c'est la solution simple.
et voici un exemple concret de travail:
/* find greatest repeated substring */
char *fgrs(const char *s,size_t *l)
{
char *r=0,*a=s;
*l=0;
while( *a )
{
char *e=strrchr(a+1,*a);
if( !e )
break;
do {
size_t t=1;
for(;&a[t]!=e && a[t]==e[t];++t);
if( t>*l )
*l=t,r=a;
while( --e!=a && *e!=*a );
} while( e!=a && *e==*a );
++a;
}
return r;
}
size_t t;
const char *p;
p=fgrs("BARBARABARBARABARBARA",&t);
while( t-- ) putchar(*p++);
p=fgrs("0123456789",&t);
while( t-- ) putchar(*p++);
p=fgrs("1111",&t);
while( t-- ) putchar(*p++);
p=fgrs("11111",&t);
while( t-- ) putchar(*p++);
Voici une solution plus générale au problème, qui trouvera des sous-séquences répétitives dans une séquence (de n'importe quoi), où les sous-séquences ne doivent pas nécessairement commencer au début, ni se suivre immédiatement.
étant donné une séquence b [0..n], contenant les données en question, et un seuil t étant la longueur minimale de sous-séquence à rechercher,
l_max = 0, i_max = 0, j_max = 0;
for (i=0; i<n-(t*2);i++) {
for (j=i+t;j<n-t; j++) {
l=0;
while (i+l<j && j+l<n && b[i+l] == b[j+l])
l++;
if (l>t) {
print "Sequence of length " + l + " found at " + i + " and " + j);
if (l>l_max) {
l_max = l;
i_max = i;
j_max = j;
}
}
}
}
if (l_max>t) {
print "longest common subsequence found at " + i_max + " and " + j_max + " (" + l_max + " long)";
}
Fondamentalement:
Je viens de comprendre cela et d’écrire du code (écrit en C #) avec beaucoup de commentaires. J'espère que cela aide quelqu'un:
// Check whether the string contains a repeating sequence.
public static bool ContainsRepeatingSequence(string str)
{
if (string.IsNullOrEmpty(str)) return false;
for (int i=0; i<str.Length; i++)
{
// Every iteration, cut down the string from i to the end.
string toCheck = str.Substring(i);
// Set N equal to half the length of the substring. At most, we have to compare half the string to half the string. If the string length is odd, the last character will not be checked against, but it will be checked in the next iteration.
int N = toCheck.Length / 2;
// Check strings of all lengths from 1 to N against the subsequent string of length 1 to N.
for (int j=1; j<=N; j++)
{
// Check from beginning to j-1, compare against j to j+j.
if (toCheck.Substring(0, j) == toCheck.Substring(j, j)) return true;
}
}
return false;
}
N'hésitez pas à poser des questions s'il n'est pas clair pourquoi cela fonctionne.
Vous ne savez pas comment vous définissez "efficacement". Pour une implémentation facile/rapide, vous pouvez le faire en Java:
private static String findSequence(String text) {
Pattern pattern = Pattern.compile("(.+?)\\1+");
Matcher matcher = pattern.matcher(text);
return matcher.matches() ? matcher.group(1) : null;
}
il essaie de trouver la chaîne la plus courte (.+?
) qui doit être répétée au moins une fois (\1+
) pour correspondre au texte d'entrée entier.
Je voudrais convertir le tableau en objet String et utiliser regex