2011-03-05 23 views
8

Tengo que escribir el programa que cuenta cuántas letras diferentes hay en la cadena. Por ejemplo, "abc" dará 3; y "abcabc" también dará 3, porque solo hay 3 letras diferentes.Cuántas letras diferentes hay en la cadena

Necesito usar pascal, pero si puede ayudar con el código en diferentes idiomas, sería muy bueno también.

Aquí está mi código que no funciona:

var s:string; 
    i,j,x,count:integer; 
    c:char; 
begin 
    clrscr; 

    Readln(s); 
    c:=s[1]; 
    x:=1; 

    Repeat 
    For i:=1 to (length(s)) do 
    begin 
    If (c=s[i]) then 
    begin 
     delete(s,i,1); 
     writeln(s); 
    end; 
    end; 
    c:=s[1]; 
    x:=x+1; 
    Until length(s)=1; 

    Writeln(x); 

x es la letra diferente contador; Tal vez mi algoritmo es muy malo ... alguna idea? Gracias.

+1

he añadido la etiqueta de Delphi también. De esta manera, obtendrá * mucho * más atención a su pregunta. Y, después de todo, Delphi y Pascal son casi lo mismo para algoritmos simples como este. –

+3

+1 para publicar el código que estás intentando que no funcionó. Parece que probablemente también deberías agregar la etiqueta de la tarea. –

+2

Simplemente curioso: ¿deberes? –

Respuesta

11

Tienes respuestas sobre cómo hacerlo, aquí es por qué su camino no funciona.

En primer lugar, intuitivamente, usted tuvo una buena idea: comience con el primer carácter de la cadena, cuéntelo (olvidó incluir el código de conteo), elimine todas las ocurrencias del mismo carácter en la cadena. La idea es ineficiente, pero funcionaría. Usted se metió en problemas con este trozo de código:

For i:=1 to (length(s)) do 
begin 
    If (c=s[i]) then 
    begin 
    delete(s,i,1); 
    end; 
end; 

El problema es, Pascal tomará el valor Length(s) cuando se establece el bucle, pero su código cambia la longitud de la cadena mediante la eliminación de caracteres (utilizando delete(s,i,1)) . Terminarás viendo mala memoria. El problema secundario es que i va a avanzar, no importa si coincide y elimina un char o no. Aquí está por qué eso es malo.

Index: 12345 
String: aabbb 

vas a probar para i = 1,2,3,4,5, en busca de a.Cuando se i 1 encontrará una coincidencia, retire el primer carácter, y la cadena va a tener este aspecto:

Index: 1234 
String: abbb 

Ahora está probando con i = 2, y no es una coincidencia, porque s [2] = b. Acabas de esquivar un a, y dado a va a permanecer en el conjunto una segunda ronda y hace que tu algoritmo cuente dos veces. El algoritmo "fijo" se parecería a esto:

i := 1; 
while i <= Length(s) do 
    if (c=s[i]) then 
    Delete(s,i,1) 
    else 
    Inc(i); 

Esto es diferente: En el ejemplo dado, si he encontrado un partido en 1, el cursor no avanza, por lo que ve a la segunda a. Además, porque estoy usando un bucle while, no un bucle for, no me puedo meter en problemas con los posibles detalles de implementación del bucle for.

Su algoritmo tiene otro problema. Después del ciclo que elimina todas las apariciones del primer carácter en cadena, está preparando el siguiente ciclo utilizando este código:

c: = s [1];

El problema es que si usted alimenta a este algoritmo de una cadena de la forma aa (longitud = 2, dos caracteres idénticos), que va a entrar en la serie, borrar o apariciones de a (los que cumplen s en una cadena vacía) y luego intente leer el primer carácter de la cadena VACÍA.

Una última palabra: su algoritmo debe manejar la cadena vacía en la entrada, devolviendo un conteo = 0. Aquí está el algoritmo fijo:

var s:string; 
    i,count:integer; 
    c:char; 
begin 
    Readln(s); 
    count:=0; 

    while Length(s) > 0 do 
    begin 
    Inc(Count); 
    c := s[1]; 
    i := 1; 
    while i <= Length(s) do 
    begin 
     If (c=s[i]) then 
     delete(s,i,1) 
     else 
     Inc(i); 
    end; 
    end; 

    Writeln(Count); 

    Readln; 
end. 
+1

+1 por proporcionar otro tipo (y probablemente muy útil para el OP) de respuesta. –

+0

Gracias por corregir mi algoritmo y muy buena respuesta. ;) –

+1

@ user646263: Observe también la ortografía de "algoritmo" (¡mientras estamos en ello!). –

1

En Python, con la explicación si quieres que para cualquier otro idioma: (Dado que querías diferentes idiomas)

s = 'aahdhdfrhr' #s is the string 
l = [] #l is an empty list of some kind. 
for i in s: #Iterate through the string 
    if i not in l: #If the list does not contain the character 
     l.append(i) #Add the character to the list 
print len(l) #Print the number of characters in the list 
2

diferentes idiomas están bien?

Ruby:

s = "abcabc" 
=> "abcabc" 
m = s.split(//) 
=> ["a", "b", "c", "a", "b", "c"] 
p = m & m 
=> ["a", "b", "c"] 
p.count 
=> 3 
+1

-1 Esto no tiene similitudes (o incluso la posibilidad de traducir fácilmente) a Pascal. No es útil en absoluto para esta pregunta. –

+0

Rechazó la votación negativa, ya que me perdí el OP diciendo que los diferentes idiomas estaban bien. Aún así, no creo que sea útil porque no es traducible a Pascal. –

+0

Supongo que podría escribir una clase TStringElements que divida y luego ordenar esos elementos y luego contarlos. No se puede traducir directamente, pero los conceptos de un lenguaje dinámico (ruby o python) se pueden expresar (a un costo de muchas más líneas de código) en un lenguaje tipado estático. –

4

yo soy un experto en Delphi, así que no sé muy bien cómo llanura restrictiva Pascal es. No obstante, se trata de Delphi:

// Returns the number of *distinct* "ANSI" characters in Str 
function NumChrs(const Str: AnsiString): integer; 
var 
    counts: array[0..255] of boolean; 
    i: Integer; 
begin 
    ZeroMemory(@counts[0], sizeof(boolean) * length(counts)); 
    for i := 1 to length(Str) do 
    counts[ord(Str[i])] := true; 
    result := 0; 
    for i := 0 to high(counts) do 
    if counts[i] then 
     inc(result); 
end; 

La primera línea se puede escribir

for i := 0 to high(counts) do 
    counts[i] := false; 

si no se puede utilizar la API de Windows (o la función de Delphi FillChar).

Si usted desea tener soporte Unicode (como en Delphi 2009+), se puede hacer

// Returns the number of *distinct* Unicode characters in Str 
function NumChrs(const Str: string): integer; 
const 
    AllocBy = 1024; 
var 
    FoundCodepoints: array of integer; 
    i: Integer; 

    procedure Push(Codepoint: integer); 
    var 
    i: Integer; 
    begin 
    for i := 0 to result - 1 do 
     if FoundCodepoints[i] = Codepoint then 
     Exit; 
    if length(FoundCodepoints) = result then 
     SetLength(FoundCodepoints, length(FoundCodepoints) + AllocBy); 
    FoundCodepoints[result] := Codepoint; 
    inc(result); 
    end; 

begin 

    result := 0; 
    for i := 1 to length(Str) do 
    Push(ord(Str[i])); 

end; 
+0

+1 ¿No sería mejor que 'array [AnsiChar] of Boolean'? Entonces obtienes deshacerse del 'ord'. –

+3

+1 para 'AnsiString', diciendo' string' después de agregar la etiqueta 'Delphi' es peligroso. Como necesita recorrer toda la matriz para contar los resultados de cualquier manera, use un 'conjunto de AnsiChar' en lugar de' matriz [0..255] '. Menos memoria, código más rápido. –

+0

'conjunto de AnsiChar' muy buena idea. Bastante molesto para contar. Realmente me encantaría que hubiera un built-in que contara los miembros del set. –

4

aquí está mi versión. No estoy diciendo que obtendrá una gran marca en su asignación si la mano en este.

function NumberOfUniqueChars(s: string): Integer; 
var 
    i, j: Integer; 
    c: char; 
begin 
    for i := 1 to Length(s) do 
    for j := i+1 to Length(s) do 
     if s[i]<s[j] then 
     begin 
     c := s[i]; 
     s[i] := s[j]; 
     s[j] := c; 
     end; 
    Result := 0; 
    for i := 1 to Length(s) do begin 
    if (i=1) or (s[i]<>c) then 
     inc(Result); 
    c := s[i]; 
    end; 
end; 
+0

+1 para una solución interesante. Ordenando primero, luego iterando y contando ... No estoy seguro de que eso es lo que el docente está buscando, pero podría obtener puntos por originalidad.

+0

+1. Esta no es una solución ingenua. Sin embargo, no estoy seguro de si hay algún aumento en la velocidad. –

+0

+1 Me gusta la idea de ordenar, especialmente útil si la cadena es Unicode. ¡Pero usaría un mejor algoritmo de clasificación! –

2

Una versión de Delphi. La misma idea que @The Communist Duck Python.

function GetNumChars(Str: string): Integer; 
var 
    s: string; 
    c: Char; 
begin 
    s := ''; 
    for c in Str do 
    begin 
     if Pos(c, s) = 0 then 
     begin 
      s := s + c; 
     end; 
    end; 
    Result := Length(s); 
end; 
+0

1) El parámetro 'Str' debe ser' const'. 2) El 'begin' y' end' no son necesarios. 3) Construir una cadena carácter por carácter es bastante ineficiente. 4) ¿Se te permite usar 'Pos' si esto es un ejercicio para escribir un algoritmo? Sin embargo, +1. –

+0

@Andreas 1) De acuerdo. 2) Me gustan :) 3) Si escaneas un libro, 's' probablemente terminará en unos 50 a 60 caracteres. No es un gran problema aquí, pero aún así es un buen punto. 4) Hmmm. No lo sé. Tal vez debería escribir su propia versión de 'Pos'. –

2

Sólo lanzando en un set ... -Alternativa

program CountUniqueChars; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils; 

var 
    InputStr: String; 
    CountedChr: Set of Char; 
    TotalCount: Integer; 
    I: Integer; 
begin 
    Write('Text: '); 
    ReadLn(InputStr); 

    CountedChr := []; 
    TotalCount := 0; 

    for I := 1 to Length(InputStr) do 
    begin 
    Write('Checking: ' + InputStr[i]); 
    if (InputStr[i] in CountedChr) 
    then WriteLn(' --') 
    else begin 
     Include(CountedChr, InputStr[i]); 
     Inc(TotalCount); 
     WriteLn(' +1') 
    end; 
    end; 


    WriteLn('Unique chars: ' + IntToStr(TotalCount)); 
    ReadLn; 
end. 
0
function CountChars(const S:AnsiString):Integer; 
var C:AnsiChar; CS:Set of AnsiChar; 
begin 
    Result := 0; 
    CS := []; 
    for C in S do 
    if not (C in CS) then 
    begin 
     CS := CS + [C]; 
     Inc(Result); 
    end; 
end; 
2

Y el uso de una construcción de Delphi (no es eficiente, pero limpio)

function returncount(basestring: String): Integer; 
var charstrings: TStringList; 
    I:Integer; 
begin 
Result := 0; 
charstrings := TStringlist.create; 
try  
    charstrings.CaseSensitive := False; 
    charstrings.Duplicates := DupIgnore; 
    for I := 1 to length(basestring) do 
    charstrings.Add(basestring[i]; 
    Result := charstrings.Count; 
finally 
    charstrings.free; 
end; 
end; 
Cuestiones relacionadas