【问题标题】:Count letters in a string计算字符串中的字母
【发布时间】:2017-11-18 20:05:17
【问题描述】:

我需要找到一种算法来计算任何字符串中的字母(例如“cababbabb”),并且输出必须按字母顺序排列(例如 a: 3, b: 4, c:1 等)。无需区分大小写字母。我不允许你使用 HashMap。

到目前为止,这是我的代码:我不工作,我认为我在这里的策略错误。你能帮帮我吗?

public class Stringray extends MiniJava{
public static void main(String[] args) {
    // Texteingabe
    String input = readString("Geben Sie einen Text ein: ");

    String output = "";
    int i = 0;

    // Häufigkeit der Buchstaben
    int count = 0;
    char letter = 'a';
    while(i < input.length()) {
            while(i < input.length()) {
                if(input.charAt(i) == letter) {
                    while(i < input.length()) {
                        count++;
                        i++;
                    }
                    output = output + letter + ": " + count + "\t";
                }
                i++;
            }
            letter++;
    }
    write(output);
}
}

【问题讨论】:

  • 您的代码不起作用,因为您首先对所有 3 个循环使用相同的索引。另外,既然您希望对输出进行排序,为什么不在即将更改为“更高”字符时对打印的字符进行排序并运行线性扫描?

标签: java count


【解决方案1】:

这是一个简单的算法:

  1. 创建一个长度为26的空数组int[],它将被初始化为0s
  2. 迭代你的字符串
  3. 在当前索引处获取char
  4. 棘手的部分:您需要在给定的char 与其对应的索引之间进行映射(例如,a 将是索引0b 将是索引1 等等)。看看这个的 ASCII 表
  5. 将 1 添加到已创建数组的映射索引处的元素。
  6. 最后,迭代数组并仅打印不是0 的值以及该索引处对应的char(此处需要再次进行ASCII 映射)

【讨论】:

    【解决方案2】:

    您可以按照以下步骤解决问题,如正确指出的 QBrute。

    public String countMatches(String main) {
        //Create an array of the alphabets length
        main = main.toLowerCase();
        int[] foundArray = new int[26];
        String output = "";
        //Create an alphabets array
        String[] alphabets = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split("\\s");
        //Split the main String array
        String[] mainArray = main.split("");
        for (String string : mainArray) {
            //Iterate through the array
            for (int i = 0; i < alphabets.length; i++) {
                //If the string index matches any of our alphabets
                if (string.equals(alphabets[i])) {
                    //Increase the corresponding foundArray index value
                    foundArray[i] = foundArray[i] + 1;
                }
            }
        }
        //Iterate through the foundArray
        for (int i = 0; i < foundArray.length; i++) {
            //If an index is greater than 0
            if (foundArray[i] > 0) {
                //A match was found
                //Assign the matched foundArray index to the corresponding alphabet
                output += alphabets[i] + ":" + foundArray[i] + ", ";
            }
        }
        return output;
    }
    

    【讨论】:

    • 感谢您的帮助。这看起来实际上非常好。但我不太确定我是否理解 "String[] alphabets = "a b c d e f g h i j k l m n o p q r s t u v w x y z".split("\\s"); for (String string : main.split("")) {" 到底发生了什么这个论点?
    • 你也可以像这样手动创建一个字母数组: String[] alphabets = {"a","b","c", "d","e","f"," g","h","i","j","k","l","m","n","o","p","q","r","s" ,"t","u","v","w","x","y","z"};或使用手动 char 数组,但比拆分它要慢。
    • 我明白了。但是此时有一个异常(main.split("")),它说“main 无法解析”;你知道这是什么意思吗?
    • 那里仍然是一个错误,但是当我使用长版本的字符串字母数组时,是否需要带有 main.split 的 for 循环?
    • 是的,你仍然需要循环。但问题并非来自那里。您是否更改了函数参数变量?我的意思是“public String countMatches(String main) {”代码的“String main”部分?如果是,那么您必须将“main”替换为您更改它的变量。
    【解决方案3】:

    在线性时间内执行此操作的一种非常有效的方法是使用 HashMap

    public class Stringray extends MiniJava {
    
        public static void main(String[] args) {
            String input = "Geben Sie einen Text ein: ";
            System.out.println(countLetters(input));
        }
    
        public static HashMap<Character, Integer> countLetters(String input) {
            HashMap<Character, Integer> hashMap = new HashMap<>();
            final int length = input.length();
            for (int i = 0; i < length; i++) {
                Character currentChar = Character.toLowerCase(input.charAt(i));
                if (Character.isAlphabetic(currentChar)) {
                    if (hashMap.containsKey(currentChar)) {
                        hashMap.put(currentChar, hashMap.get(currentChar) + 1);
                    } else {
                        hashMap.put(currentChar, 1);
                    }
                }
            }
            return hashMap;
        }
    
    }
    

    您需要考虑大写和小写相同并丢弃非字母字符。一旦你在 hashmap 中获得了所有信息,你在控制台中显示它的方式是另一回事。如果您需要为文本中不存在的字母显示零,最好将哈希图初始化为该值。

    【讨论】:

    • 非常感谢,但我不允许使用 hashMap。
    【解决方案4】:

    我不确定这是否是一个技巧问题。但实际上你所要做的似乎就是创建一个计算字符串中字符出现次数的方法。下面的代码如何做到这一点是最简单的方法。我把它留给你修改它,使它适合你所有的测试用例。

    public static void main(String[] args)
    {
        String input = "cabababb";
        char[] testCharacters = new char[] { 'a', 'b', 'c' };
        for (int i = 0; i < testCharacters.length; i++)
        {
            System.out.println(testCharacters[i] + " occurs " + countOccurencesOf(testCharacters[i], input));
        }
    }
    
    public static int countOccurencesOf(char aCharacter, String inThisString)
    {
        int count = 0;
        for (int i = 0; i < inThisString.length(); i++)
        {
            if (aCharacter == inThisString.charAt(i)) { count++; }
        }
        return count;
    }
    

    【讨论】:

      【解决方案5】:

      我为你整理了一个字符冒泡排序。还有其他方法可以用更少的代码做到这一点,使用内置的排序方法,但这个展示了数组排序的工作原理。

      这不考虑会改变其数字 Unicode 值的大小写字母,但这会让您朝着正确的方向前进。

          public static void main(String[] args) {
      
          char[] str = "cabababb".toCharArray(); //Turn your string into an array
      
          int n = str.length; //get the length of the array
          char temp; //a temporary character holder
          for (int i = 0; i < n; i++) {
              for (int j = 1; j < (n - i); j++) {
                  int compare = Character.getNumericValue(str[j - 1]);//get the numeric value of the char
                  int compareTo = Character.getNumericValue(str[j]); //etc
                  if (compare > compareTo) {//do a compare
                      //swap elements  
                      temp = str[j - 1]; //bubble sort
                      str[j - 1] = str[j];
                      str[j] = temp;
                  }
      
              }
          }
          System.out.println(Arrays.toString(str));//You get your sorted array
      
      
      }
      

      冒泡排序背后的概念是这样的:

      如果您的数组读取 ['x','j']

      如果前一个数组迭代大于当前数组迭代,这两个变量将进入带有注释//do a compare 的 if 语句:

      1. 它将前一个字符放入“临时”变量中
      2. 那么它将用当前字符替换前一个字符
      3. 最后,它会将当前字符作为前一个字符(另存为“temp”)

      回到例子:

      ['x','j']

      if('x' > 'j'){//for example's sake **Not real code**
      //x is in 0 position
      //j is in 1 position
                      temp = 0 position's value; 
                      0 position's value = 1 position's value;
                      1 position's value = temp;
      }
      

      最后你会得到一个按字母顺序排列的数组。

      如果您需要将其重新转换为字符串,您可以将其连接回字符串

      String newStr = "";
      
              for(char letter : str){
      
                 newStr += letter;
      
              }
      
      
      
              System.out.println(newStr);
      

      我希望这可以帮助您理解 Java 中排序背后的概念

      【讨论】:

        【解决方案6】:

        需求需要一些分析。

        有一个非功能性要求不使用哈希映射。哈希映射只是一种以牺牲一点时间为代价减少稀疏数据存储需求的方法。它易于使用,但在 Java 中使代码更加复杂。因此,直接的方法是使用数组。希望内存便宜。

        功能需求问题较多:

        • 字母: Unicode 是 Java 使用的字符集,它确实有指定的字母 Character.isLetter
        • 字母顺序:语言学院和流行的惯例决定了字母表中的字母以及该语言的各种书写系统中的字母顺序。由于没有提到任何语言或脚本,让我们对此进行抨击,并使用字符集的代码点顺序(字典顺序)并报告每个字母。
        • 不需要区分大小写字母:因为字母大小写是特定于文化/区域设置的,所以单独查看每个字母而不是尝试定义大写集合确实会更直接和小写字母。 (无论如何还有更多的情况。)它似乎是一个选项,所以让我们现在跳过它。

        .

        int[] codepointCounts = new int[Character.MAX_CODE_POINT + 1]; // min to max, inclusive
        
        String input = "Häufigkeit der Buchstaben";
        
        for(int c : input.codePoints().toArray()){ 
            codepointCounts[c]++;       
        }
        for (int c = Character.MIN_CODE_POINT; c <= Character.MAX_CODE_POINT; c++) {
            if (codepointCounts[c] > 0) { 
                if (Character.isLetter(c)) {
                    write(
                        new String(Character.toChars(c)) + '\t' + 
                        codepointCounts[c] + '\t' + 
                        Character.getName(c));
                }
            }
        }
        

        【讨论】:

        • 好点。关于上和下,如果需要对“A”和“a”进行排序,我提供的代码没有考虑到这一点。我应该措辞更好一些。好点。
        猜你喜欢
        • 2014-07-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-28
        • 1970-01-01
        • 2023-03-25
        相关资源
        最近更新 更多