String 字符串中有多少个不同的字母

String 字符串中有多少个不同的字母,string,delphi,pascal,String,Delphi,Pascal,我必须编写一个程序来计算字符串中有多少个不同的字母。 例如,“abc”将给出3;“abcabc”也会给出3,因为只有3个不同的字母 我需要使用pascal,但如果你能帮助编写不同语言的代码,那也会很好 以下是我的代码,它不起作用: 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)

我必须编写一个程序来计算字符串中有多少个不同的字母。 例如,“abc”将给出3;“abcabc”也会给出3,因为只有3个不同的字母

我需要使用pascal,但如果你能帮助编写不同语言的代码,那也会很好

以下是我的代码,它不起作用:

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是不同的字母计数器;
也许我的算法很差。。有什么想法吗?谢谢。

在Python中,如果您需要其他语言,请提供解释:(因为您需要不同的语言)


不同的语言可以吗

红宝石:


我是一名德尔菲专家,所以我不太知道普通帕斯卡的限制性有多大。然而,这是德尔福:

// 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;
第一行可以写

  for i := 0 to high(counts) do
    counts[i] := false;
如果无法使用Windows API(或Delphi
FillChar
函数)

如果您希望获得Unicode支持(如Delphi 2009+),您可以这样做

// 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;

这是我的版本。我并不是说如果你交上这个作业,你会在作业中获得高分

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;
函数NumberOfUniqueChars(s:string):整数;
变量
i、 j:整数;
c:半焦;
开始
对于i:=1到长度do
对于j:=i+1到长度do

如果你已经找到了如何做的答案,这就是为什么你的方法行不通

首先,直观地说,您有一个好主意:从字符串中的第一个字符开始,对其进行计数(您忘记包含计数代码),删除字符串中出现的所有相同字符。这个想法效率不高,但会奏效。您遇到了这段代码的问题:

For i:=1 to (length(s)) do
begin
  If (c=s[i]) then
  begin
    delete(s,i,1);
  end;
end;
问题是,Pascal在设置循环时将采用
Length(s)
值,但是您的代码通过删除字符(使用
delete(s,i,1)
)来更改字符串的长度。你最终会看到糟糕的记忆。第二个问题是,
i
将前进,它是否匹配并删除了一个字符并不重要。这就是为什么这很糟糕

Index:  12345
String: aabbb
您将测试i=1,2,3,4,5,查找
a
。当
i
为1时,您将找到一个匹配项,删除第一个字符,您的字符串将如下所示:

Index:  1234
String: abbb
i := 1;
while i <= Length(s) do
  if (c=s[i]) then
    Delete(s,i,1)
  else
    Inc(i);
您现在使用i=2进行测试,但它不是匹配项,因为s[2]=b。您刚刚跳过了一个
a
,而给定的
a
将在另一轮中保留在数组中,并使您的算法对其进行两次计数。“固定”算法如下所示:

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

德尔福版本。与@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;

只是在
集合中翻滚
-备选方案

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.

并使用Delphi构造(不是高效的,而是干净的)


我还添加了Delphi标签。这样,你的问题会得到更多的关注。毕竟,对于像这样的简单算法来说,Delphi和Pascal几乎是一样的。发布你正在尝试但不起作用的代码的+1。看起来您也应该添加家庭作业标记。+1使用布尔值的
数组[AnsiChar]不是更好吗?然后,您就可以去掉
ord
+1 for
AnsiString
,在添加
Delphi
标记后说
string
,这是危险的。由于您需要在整个数组上循环以对结果进行任何方式的计数,因此请使用AnsiChar的
集来代替
数组[0..255]
。更少的内存,更快的代码。
一套AnsiChar
非常好的主意。数数起来很烦人。我真的很想有一个内置的计数集成员。这是成为高尔夫@Cosmin:可以用一个新的答案写下你自己的版本!这也会给你一些分数@Andreas,写另一个答案来改变仅仅3行代码似乎很愚蠢。将其作为@user646263的练习可能更好。-1这与Pascal没有相似之处(甚至不可能轻松翻译)。这对这个问题一点帮助都没有。收回了否决票,因为我错过了OP,说不同的语言都可以。但仍然不认为它有用,因为它不可翻译为Pascal。我想您可以编写一个TStringElements类来拆分这些元素,然后对它们进行排序,然后对它们进行计数。它不是直接可翻译的,但是动态语言(ruby或python)的概念可以用静态类型的语言表达(需要花费更多的代码行)。+1是一个有趣的解决方案。先排序,然后迭代和计数。。。不确定这是老师想要的,但它可能会因为独创性而得到分数+1.这不是一个天真的解决方案。不过,我不确定速度是否有所提高。+1我喜欢排序的想法,尤其是在字符串是Unicode的情况下。但我会使用更好的排序算法!我的第一个(仅ANSI)函数,我的第二个(Unicode)函数,您的函数:282281285781967587(刻度)。[这些值是基于一个天真的比较,然而!]@David:为了增加创意的另一个维度,你应该替换
c:=s[i];s[i]:=s[j];s[j]:=cs[i]:=Chr(Ord(s[i])或xor Ord(s[j]);s[j]:=Chr(Ord(s[i])xor Ord(s[j]);s[i]:=Chr(Ord(s[i])xor Ord(s[j])+1,用于提供另一种答案(可能对OP非常有帮助)。感谢您纠正我的算法并给出非常好的答案。;)@user646263:请注意“algorithm”的拼写(我们在这里!)。1)
Str
参数应该是
const
。2) 不需要
开始
结束
。3) 一个字符一个字符地建立一个字符串效率很低。4) 如果这是编写算法的练习,是否允许使用
Pos
?然而,+1.@Andreas同意。2) 我喜欢:)。3) 如果你扫描一本书,
s
可能会以50到60个字符结束。这不是一个大问题,但仍然是一个很好的观点。4) 嗯,我不知道。也许他应该编写自己版本的
Pos
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.
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;
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;