Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How many different letters are in string

I have to write program that counts how many different letters are in string. For example "abc" will give 3; and "abcabc" will give 3 too, because there are only 3 different letters.

I need to use pascal, but if you can help with code in different languages it would be very nice too.

Here is my code that does not work:

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 is the different letter counter; Maybe my algorythm is very bad.. any ideas? Thank you.

like image 638
va. Avatar asked Mar 05 '11 20:03

va.


1 Answers

You've got answers on how to do it, here's why your way doesn't work.

First of all intuitively you had a good idea: Start with the first char in the string, count it (you forgot to include the counting code), remove all occurrences of the same char in the string. The idea is inefficient, but it would work. You ran into trouble with this bit of code:

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

The trouble is, Pascal will take the Length(s) value when it sets up the loop, but your code changes the length of the string by removing chars (using delete(s,i,1)). You'll end up looking at bad memory. The secondary issue is that i is going to advance, it doesn't matter if it matched and removed an char or not. Here's why that's bad.

Index:  12345
String: aabbb

You're going to test for i=1,2,3,4,5, looking for a. When i is 1 you'll find a match, remove the first char, and your string is going to look like this:

Index:  1234
String: abbb

You're now testing with i=2, and it's not a match, because s[2] =b. You just skiped one a, and that given a is going to stay in the array an other round and cause your algorithm to count it twice. The "fixed" algorithm would look like this:

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

This is different: In the given example, if I found a match at 1, the cursor doesn't advance, so it sees the second a. Also because I'm using a while loop, not a for loop, I can't get in trouble with possible implementation details of the for loop.

Your algorithm has an other problem. After the loop that removes all occurrences of the first char in string you're preparing the next loop using this code:

c:=s[1];

The trouble is, if you feed this algorithm an string of the form aa (length=2, two identical chars), it's going to enter the loop, delete or occurrences of a (those turning s into an EMPTY string) and then attempt to read the first char of the EMPTY string.

One final word: Your algorithm should handle the empty string on input, returning an count=0. Here's the fixed algorithm:

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.
like image 191
Cosmin Prund Avatar answered Sep 30 '22 23:09

Cosmin Prund