Contare caratteri distinti in una stringa in Object pascal
Buon giorno, ho creato questo codice che dovrebbe contare caratteri distinti in una stringa, il mio codice è stato testato da diversi input ma non è riuscito a contare i caratteri in questo input:
zcinitufxoldnokacdvtmdohsfdjepyfioyvclhmujiqwvmudbfjzxjfqqxjmoiyxrfsbvseawwoyynn
ha quasi 80 caratteri e la stringa massima che Pascal può leggere ha la lunghezza di 256 caratteri. Non sono riuscito a trovare un algoritmo migliore per risolvere questo problema, quindi sto cercando aiuto dagli esperti in questo campo o da chiunque sia aperto a condividere le conoscenze.
Immagino che il mio codice salti un carattere in ogni ciclo.
Ecco il mio codice:
function freq(char: char; username : String): Integer;
var
i, auxfreq: Integer;
begin
auxfreq:= 0;
for i:= 1 to length(username) do
if char = username[i] then
auxfreq:= auxfreq + 1;
//writeln(freq);
freq:= auxfreq;
end;
function OddUserName(username : String): Boolean;
var
usernameaux : String;
length_usernameaux, i : Integer;
Result : Boolean;
begin
Result:= false;
usernameaux:= username;
i:= 0;
repeat
i +=1;
length_usernameaux:= length(usernameaux);
if freq(usernameaux[i], usernameaux) <> 1 then
delete(usernameaux, i, 1);
until i = length_usernameaux;
// length(usernameaux) is supposed to be the number of the distinct characters.
{if length(usernameaux) mod 2 <> 0 then // you will have to ignore this.
Result:= true; // odd}
//writeln(usernameaux);
//writeln(length(usernameaux));
OddUserName:= Result; // ignore this too
end;
Apprezzo sinceramente il tuo aiuto.
Risposte
Non stai tenendo adeguatamente conto della modifica della lunghezza di una stringa quando delete()inserisci caratteri da essa.
Se usernameè vuoto, si finisce per accedere a caratteri non validi poiché il repeatciclo tenta di accedere a un carattere all'indice 1, che non esiste. In realtà, finisci in un ciclo infinito poiché i = length_usernameauxsarà sempre Falso poiché iinizia da 1 e aumenta verso l'alto ma length_usernameauxè sempre 0 (beh, almeno, il ciclo viene eseguito fino ia quando non supera un valore negativo e alla fine aumenta fino a 0, ma di quella volta probabilmente hai bloccato il tuo codice prima che accadesse).
Se usernamenon è vuoto, si incrementa ia ogni iterazione del ciclo, che salterà il carattere successivo quando si delete()inserisce un carattere in i. ideve rimanere allo stesso indice ogni volta che un carattere è delete()'d, poiché il carattere successivo scorrerà verso il basso per occupare l'indice del carattere che era solo delete' d. Incrementa isolo quando NON delete()stai inserendo un personaggio.
Prova questo invece:
function freq(charToFind: char; username : String): Integer;
var
i, auxfreq: Integer;
begin
auxfreq := 0;
for i := 1 to Length(username) do
begin
if charToFind = username[i] then
auxfreq := auxfreq + 1;
end;
//writeln(freq);
freq := auxfreq;
end;
function OddUserName(username : String): Boolean;
var
usernameaux : String;
length_usernameaux, i : Integer;
Result : Boolean;
begin
Result := false;
usernameaux := username;
length_usernameaux := Length(usernameaux);
i := 1;
while i <= length_usernameaux do
begin
if freq(usernameaux[i], usernameaux) > 1 then
begin
Delete(usernameaux, i, 1);
length_usernameaux := length_usernameaux - 1;
end else
begin
i = i + 1;
end;
end;
// length_usernameaux is supposed to be the number of the distinct characters.
{if length_usernameaux mod 2 <> 0 then // you will have to ignore this.
Result := true; // odd}
//writeln(usernameaux);
//writeln(length_usernameaux);
OddUserName := Result; // ignore this too
end;
Se hai solo bisogno di ottenere il numero di caratteri distinti in una stringa, puoi usare qualcosa di semplice come questo:
function CountDistinctCharacters(InputString: string): Integer;
var I: Integer;
//String for storing all distinct characters
DistinctChars: string;
begin
//Loop trough every character in input string
for I := 1 to Length(InputString) do
begin
//Use Pos function to find position of specific character in DistinctChars string
//Function returns 0 if character is not found
if Pos(InputString[I], DistinctChars) = 0 then
begin
//If character isn't found in DistinctChars string add it to it
DistinctChars := DistinctChars+InputString[I];
end;
end;
//Finaly check the lenght of DistinctChars string to get the number of distinct character
//found and return it as function result
Result := Length(DistinctChars);
end;
Se hai anche bisogno di informazioni su quali caratteri sono presenti nella tua stringa di input, invece di usare la DistinctCharsvariabile di stringa locale, puoi passare una stringa come var pamaeter alla tua funzione in questo modo:
//Pass external string as var parameter to your function in order to allow function to
//fill it with all distinct characters
function CountDistinctCharacters(InputString: string; var DistinctChars: string): Integer;
var I: Integer;
begin
//Loop trough every character in input string
for I := 1 to Length(InputString) do
begin
//Use Pos function to find position of specific character in DistinctChars string
//Function returns 0 if character is not found
if Pos(InputString[I], DistinctChars) = 0 then
begin
//If character isn't found in DistinctChars string add it to it
DistinctChars := DistinctChars+InputString[I];
end;
end;
//Finaly check the lenght of DistinctChars string to get the number of distinct character
//found and return it as function result
Result := Length(DistinctChars);
end;
Ma se desideri anche informazioni sul numero di caratteri presenti nella stringa di input, dovrai utilizzare una struttura dati per il risultato che consenta di memorizzare coppie di dati come TDictionary o forse array di record in cui ogni record memorizza coppie di informazioni (carattere e numero di occorrenze).
Sono riuscito a sistemare le cose a modo mio, in questo modo grazie al tuo aiuto. Tutto quello che ho fatto è diminuire l'indice di uno dopo aver eliminato il carattere duplicato. Come questo :
function OddUserName(username : String): Boolean;
var
usernameaux : String;
length_usernameaux, i : Integer;
//Result : Boolean;
begin
Result:= false;
usernameaux:= username;
i:= 0;
repeat
i +=1;
length_usernameaux:= length(usernameaux);
if freq(usernameaux[i], usernameaux) <> 1 then
begin
delete(usernameaux, i, 1);
i-=1; // <----- added
end;
until i = length_usernameaux;
if length(usernameaux) mod 2 <> 0 then
Result:= true; // odd
//writeln(usernameaux);
//writeln(length(usernameaux));
OddUserName:= Result;
end;