【问题标题】:Character counter in JavaJava中的字符计数器
【发布时间】:2013-08-01 13:11:02
【问题描述】:

到目前为止,这是我尝试过的:

public class CharacterCounter {

public static void main(String[] args){

    String string = "sashimi";

    int count = 0;
    for(int i =0; i < string.length(); i++){
        if(string.charAt(i) == 'i'){
            count++;
            }
    }

    System.out.println("The number of letter i is " + count);

} 
}

输出:

 The number of letter i is 2

但我想做的是,程序应该计算出现次数最多的字符。

例如这里的字符串是SASHIMI,输出应该是:

 the number of letter S is 2
 the number of letter I is 2

我被这个问题困住了。我需要你的帮助。谢谢。

【问题讨论】:

  • 您应该使用HashMap &lt;Character, Integer&gt;。关键是一个字符。该值为出现的次数。
  • 也许你应该使用某种map,其中字符是键,它的频率是值。然后,您可以遍历映射并找到具有最高值的键。
  • int[1&lt;&lt;16] 也会做得很好,而且性能要好得多。事实上,速度很快。
  • @Marko 你能详细点吗?我不明白它的作用。
  • @ArnaudDenoyelle 请参阅下面的答案。

标签: java


【解决方案1】:

这是最快的方法:

final int[] counts = new int[1<<16];

for (char c : <your_string>)
  counts[c]++;

(我刚刚勾勒出遍历所有字符的部分,我相信这是简单的部分,与这个问题没有直接关系)。

基准测试结果

我用三个字符串长度将HashMap 方法与我的方法进行了对比:

  1. 10
  2. 1,000
  3. 100,000

结果如下:

Benchmark       Mode Thr    Cnt  Sec         Mean   Mean error    Units
testArray1      thrpt   1      5    5        6.870        0.083 ops/msec
testArray2      thrpt   1      5    5        6.720        0.374 ops/msec
testArray3      thrpt   1      5    5        3.770        0.019 ops/msec
testHashMap1    thrpt   1      5    5     1269.123      251.766 ops/msec
testHashMap2    thrpt   1      5    5       12.776        0.165 ops/msec
testHashMap3    thrpt   1      5    5        0.141        0.005 ops/msec

它们是什么意思?是的,将一个完整的 512K 内存块初始化为零是昂贵的。但是在付费之后,我的数组算法甚至几乎没有注意到成千上万的字符呼啸而过。另一方面,HashMap 方法对于非常短的字符串要快得多,但扩展性要差得多。我猜交叉的字符串长度约为 2k。

我想这样的字符数统计通常是针对大量文本语料库而不是像你的名字和姓氏这样的东西运行的,这一点没有争议。

当然,如果您可以假设不使用完整的 UTF-16 代码点范围,则数组方法的性能可以大大提高。例如,如果您使用仅容纳最低 1024 个代码点的数组,则性能将提高到 470 ops/msec。

【讨论】:

  • 它比只处理长字符串的 map 更快 - 对于短字符串,数组的初始化可能比处理 map 花费更多的时间
  • 好的,这可能是最快的,但我会选择排序选项。
  • @gawi 你对它进行了基准测试吗?一次分配 64k 个整数几乎不需要任何东西。相反,HashMap 是一个需要初始化的复杂对象。更不用说维护该 HashMap 所需的所有工作了。我接受您的挑战并对此进行测试。
  • 我想您可以补充一下,是否有理由采用最快的方式 - 您是否认为其他方法会导致瓶颈?它真的会快多少?为什么?
  • @eis 不仅速度快,而且是最简单直接的方式。如果速度是通过一些极其复杂的黑客获得的,那将是另一回事。
【解决方案2】:
    char[] chars = string.toCharArray();
    HashMap<Character, Integer> countMap = new HashMap<Character, Integer>();
    for (char aChar : chars) {
        if (countMap.containsKey(aChar)) {
            countMap.put(aChar, countMap.get(aChar) + 1);
        } else {
            countMap.put(aChar,1);
        }
    }

    //determine max occurence
    int max = 0;
    for (Integer i: countMap.values()) {
        if (max < i) {
            max = i;
        }
    }

    //print all satisfiying max occurrence
    for (Map.Entry<Character, Integer> e: countMap.entrySet()) {
        if (e.getValue() == max) {
            System.out.println("The number of letter " + e.getKey() + "  is " + max);
        }
    }

【讨论】:

    【解决方案3】:

    我相信使用原语会比使用HashMap 更快。 This works:

    public static void main(String[] args)
    {
        final String string = "sashimi";
        final int counters[] = new int[256]; // assuming you would use only ASCII chars
        for (final char c : string.toCharArray())
        {
            counters[c]++;
        }
        int maxCounter = 0;
        for (final int counter : counters)
        {
            if (maxCounter < counter)
            {
                maxCounter = counter;
            }
        }
        for (int i = 0; i < counters.length; i++)
        {
            if (counters[i] == maxCounter)
            {
                System.out.printf("%c has %d occurences.\n", i, counters[i]);
            }
        }
    }
    

    输出:

    i has 2 occurences.
    s has 2 occurences.
    

    【讨论】:

      【解决方案4】:

      正如 cmets 中提到的,HashMap 似乎很适合这个,虽然我不会给你直接代码,我会给你一个伪代码模板。

      for(each letter in a word)
      {
          if(this letter (l) exists in your hash map)
          {
               hashmap.put(l, hashmap.get(l) ++);
          }
          else
          {
               hashmap.put(l, 1);
          }
      }
      

      这将为您提供所有字母的哈希图,映射到它们在单词中出现的次数。按照你的例子:

      S => 2
      A => 1
      H => 1
      I => 2
      M => 1
      

      【讨论】:

        【解决方案5】:

        我建议你创建一个 TreeSet,然后你可以有一个新的类来存储字符和出现的次数,然后你可以让那个类有一个 compareTo 来检查出现的情况和一个 equals 来检查 char。然后,每当您将它们插入树集中时,它们将始终按照出现次数最多的顺序排列。

        如果您需要这方面的帮助,或者您是否可以通过此信息解决问题,请告诉我 :)

        编辑:一旦你用所有的字母填充了 TreeSet,你所要做的就是开始一个一个地把它们取出来,直到你取出的那个的出现次数少于你之前取出的那个(即, 如果前 3 个字母出现 3 次,第四个字母出现 2 次,则只显示前 3 个)。

        【讨论】:

          【解决方案6】:

          您必须使用HashMap 来保留重复次数最多的字符并打印出来。

          【讨论】:

          • 最后? HashMap 还是 ArrayList ? xD
          • 两个arrayLists 或一个hashmap 取决于你想做什么,HashMap 有开销但搜索速度更快。
          【解决方案7】:

          你需要做的是获取文字(字符串)。并查看它的每个字符并将其放入适当的桶中。换句话说,您需要将它们分组。

          您可以为每个字母创建一个存储桶。然后您可以将字符放入适当的桶中,最后计算其中的项目以获得答案。

          请参阅 Marko 的答案,即这样做。

          另一种选择是您对文字AHIIMSS 进行排序,然后使用简单的循环您将能够编写结果。

          您选择的方法取决于您需要获得的结果。如果您需要找出每个字母在 word 中使用的数量,那么排序选项会更流行,如果您只需要选择最大的字母,那么使用桶的解决方案会更有用。

          【讨论】:

            【解决方案8】:

            导入 java.util.*;

            公共类 CharacterCounter {

            public static void main(String[] args){

            String string = "sashimi";
            int count = 0;
            ArrayList<Character> c = new ArrayList<Character>();
            for(int i =0; i <string.length(); i++)
            {
                count=0;
                if(c.contains(string.charAt(i)))
                {
                    continue;
                }   
                c.add(string.charAt(i));        
                for(int j = 0;j<string.length();j++)
                {
            
                    if(string.charAt(j) == string.charAt(i))
                    {
            
                        count++;
            
                    }
            
            
                }
                System.out.println("The number of letter "+string.charAt(i)+" is " + count);
            }
            

            } }

            【讨论】:

              【解决方案9】:
                  String str = "sashimi";
                  Map<Character,Integer> countMap=new HashMap<Character,Integer>();
                  Set<Character> maxcSet=new HashSet<Character>();
                  Character maxC=null;
                  Integer maxCount=null;
                  for (int i = 0; i < str.length(); i++) {
                      char c=str.charAt(i);
                      Integer tempCount=countMap.get(c);
              
                      if(tempCount==null){
                          tempCount=0;
                      }
              
                      ++tempCount;
              
                      if(i==0){
                          maxCount=tempCount;
                          maxC=c;
                      }else if(tempCount!=null){
                          if(maxCount<tempCount){
                              maxC=c;
                              maxCount=tempCount;
                              maxcSet.clear();
                              maxcSet.add(maxC);
                          }else if(maxCount==tempCount){
                              maxcSet.add(c);
                          }
                      }
                      countMap.put(c, tempCount);
                  }
              
                  System.out.println("The number of letter i is " + maxcSet);
              

              【讨论】:

                【解决方案10】:
                import java.util.Scanner;
                
                
                public class CountingCharecter {
                public static void main(String[] args) throws Exception {
                    ///Reading Data String from keyboard
                    int count=0;
                    System.out.println("Enter Your String:");
                    Scanner sc = new Scanner(System.in);
                    String s1 = sc.nextLine();
                    //// Reading `Character` Data from Keyboard
                    System.out.println("Enter an character:");
                    //Here we read the character from console type cast the character because the read() return type is int
                    char ch =(char)System.in.read();
                    for(int i=0;i<s1.length();i++){
                           char c = s1.charAt(i);
                           if(c==ch){
                               count++;
                           }//if
                
                
                    }//for
                    System.out.println("The Number of character which you want to search is having: "+count+" Times");
                }
                }//CharecterCount
                /*
                

                输入:- 输入您的字符串:Manash 输入一个字符:a 输出:- 2

                */

                【讨论】:

                  【解决方案11】:
                   public static int numberOfOccurence(String yourString, char needle) {
                        int nb = 0;
                        for (int i=0; i < yourString.length(); i++)
                      {
                          if (yourString.charAt(i) == needle)
                                     nb++;
                  
                      }
                      return nb;
                  }
                  

                  你也可以使用 Pattern 和 Matcher :

                     Pattern pattern = Pattern.compile("i");
                     Matcher  matcher = pattern.matcher("saigigd");
                  
                     int count = 0;
                     while (matcher.find())
                     count++;
                     System.out.println(count); 
                  

                  【讨论】:

                  • 您是否考虑过该算法的成本?
                  • 您需要对字母表中的每个字母都这样做。
                  • 我只给出两个解决方案,第一个,不需要在整个字母表中搜索。通常我们会否决糟糕的解决方案,但情况并非如此,您可能会建议上述解决方案以了解内存问题。但是感谢您的关注
                  • 在这两种解决方案中,您至少需要遍历输入中的每个唯一字母。
                  猜你喜欢
                  • 2020-02-13
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多