Contare caratteri distinti in una stringa in Object pascal

Sep 11 2020

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

1 RemyLebeau Sep 11 2020 at 02:56

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;
2 SilverWarior Sep 11 2020 at 04:03

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).

1 CouldnoTB-Zone Sep 11 2020 at 04:59

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;