【问题标题】:How many different letters are in string字符串中有多少个不同的字母
【发布时间】:2011-03-05 20:04:04
【问题描述】:

我必须编写程序来计算字符串中有多少个不同的字母。 例如“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 是不同的字母计数器; 也许我的算法很糟糕..有什么想法吗?谢谢。

【问题讨论】:

  • 我也添加了 Delphi 标签。这样,您的问题会得到很多更多的关注。而且,毕竟对于像这样的简单算法,Delphi 和 Pascal 几乎是一回事。
  • +1 用于发布您尝试但不起作用的代码。看来您也应该添加作业标签。

标签: string delphi pascal


【解决方案1】:

你已经得到了如何做的答案,这就是你的方法行不通的原因。

首先直观地你有一个好主意:从字符串中的第一个字符开始,计算它(你忘了包括计数代码),删除字符串中所有出现的相同字符。这个想法效率低下,但它会奏效。这段代码你遇到了麻烦:

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=2 进行测试,但它不匹配,因为 s[2] =b。您刚刚跳过了一个 a,而给定的 a 将在另一轮中停留在数组中,并导致您的算法对其进行两次计数。 “固定”算法如下所示:

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

这是不同的:在给定的示例中,如果我在 1 找到匹配项,则光标不会前进,因此它会看到第二个 a。另外,因为我使用的是while 循环,而不是for 循环,所以我不会在for 循环的可能实现细节上遇到麻烦。

您的算法还有其他问题。在删除字符串中所有出现的第一个字符的循环之后,您正在使用以下代码准备下一个循环:

c:=s[1];

问题是,如果你给这个算法一个aa形式的字符串(长度=2,两个相同的字符),它会进入循环,删除或出现a(那些把s变成一个EMPTY 字符串),然后尝试读取 EMPTY 字符串的第一个字符。

最后一句话:您的算法应该处理输入时的空字符串,返回 count=0。这是固定算法:

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 用于提供另一种(并且可能对 OP 非常有帮助)的答案。
  • 感谢您纠正我的算法和非常好的答案。 ;)
  • @user646263:还要注意“算法”的拼写(当我们使用它时!)。
【解决方案2】:

我是 Delphi 专家,所以我不太了解普通 Pascal 的限制性。然而,这是德尔福:

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

【讨论】:

  • +1 使用array [AnsiChar] of Boolean 会不会更好?然后你摆脱ord
  • +1 表示AnsiString,在添加Delphi 标签后说string 很危险。由于您需要遍历整个数组来以任何方式计算结果,请使用set of AnsiChar 代替array[0..255]。更少的内存,更快的代码。
  • set of AnsiChar 好主意。算起来比较烦。真的很想有一个计算集合成员的内置函数。
  • 这变成了打高尔夫球! @Cosmin:随意在新答案中编写您自己的版本!这也会给你加分!
  • @Andreas,写另一个答案来改变 3 行代码似乎很愚蠢。将其作为@user646263 的练习可能会更好。
【解决方案3】:

这是我的版本。我并不是说如果你把这个交出来,你的作业就会得到很好的分数。

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;

【讨论】:

  • +1 以获得有趣的解决方案。先排序,然后迭代和计数......不确定这是老师要找的,但它可能会因原创性而得分。
  • +1。这不是一个天真的解决方案。不过,我不确定速度是否有所提高。
  • +1 我喜欢排序的想法,如果字符串是 Unicode 则特别有用。但我会使用更好的排序算法!
  • 我的第一个(仅 ANSI)函数,我的第二个(Unicode)函数,你的函数:28228、128578、1967587(刻度)。 [然而,这些值是基于简单的比较!]
  • @David:只是为了增加一个原创性维度,你应该用s[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]));替换c := s[i]; s[i] := s[j]; s[j] := c;
【解决方案4】:

并使用 Delphi 构造(效率不高,但干净)

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;

【讨论】:

    【解决方案5】:

    不同的语言都可以吗?

    红宝石:

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

    【讨论】:

    • -1 这与 Pascal 没有相似之处(甚至不可能轻松翻译)。对这个问题一点帮助都没有。
    • 收回了反对票,因为我错过了 OP 说不同的语言都可以。仍然不认为它有帮助,因为它不能翻译成 Pascal。
    • 我想您可以编写一个 TStringElements 类来拆分然后对这些元素进行排序,然后对它们进行计数。它不能直接翻译,但动态语言(ruby 或 python)的概念可以用静态类型语言表达(以更多行代码为代价)。
    【解决方案6】:

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

    【讨论】:

    • 1) Str 参数应该是 const。 2) beginend 不是必需的。 3) 逐个字符地建立一个字符串是相当低效的。 4) 如果这是编写算法的练习,您是否可以使用Pos?尽管如此,+1。
    • @Andreas 1) 同意。 2)我喜欢他们:)。 3) 如果你扫描一本书s 可能会以大约 50 到 60 个字符结束。这不是一个大问题,但它仍然是一个好点。 4)嗯。我不知道。也许他应该写自己的Pos
    【解决方案7】:

    只是折腾set-alternative...

    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.
    

    【讨论】:

      【解决方案8】:

      在 Python 中,如果您想要任何其他语言,请附上说明:(因为您想要不同的语言)

      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
      

      【讨论】:

        【解决方案9】:
        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;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-30
          • 2019-11-03
          • 1970-01-01
          • 2014-10-17
          • 2012-11-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多