PTA 題解:jmu-Java&Python-統計文字中的單詞數量並按出現次數排序


題目說明

題干

測試數據 1

輸入樣例

failure is probably the fortification in your pole

it is like a peek your wallet as the thief when you
are thinking how to spend several hard-won lepta

when you are wondering whether new money it has laid
background because of you then at the heart of the

most lax alert and most low awareness and left it

godsend failed
!!!!!

輸出樣例

46
the=4
it=3
you=3
and=2
are=2
is=2
most=2
of=2
when=2
your=2

測試數據 2

輸入樣例

Failure is probably The fortification in your pole!

It is like a peek your wallet as the thief when You
are thinking how to. spend several hard-won lepta.

when yoU are? wondering whether new money it has laid
background Because of: yOu?, then at the heart of the
Tom say: Who is the best? No one dare to say yes.
most lax alert and! most low awareness and* left it

godsend failed
!!!!!

輸出樣例

54
the=5
is=3
it=3
you=3
and=2
are=2
most=2
of=2
say=2
to=2

題目分析

這道題目的綜合性很強,涉及了多個 Java 的基本語法和用法,通過這道題的練習可以一次掌握多個知識點。題目需要解決的問題有:

  1. 單詞輸入並去除標點符號:程序需要用不定行輸入的方式輸入多行字符串,並且將字符串分割成多個單詞。其中字符串會存在不少標點符號和空格,這些標點符號可能和單詞相鄰,因此不能簡單地直接分割字符串。
  2. 統計詞頻:對於輸入的字符串,不同的單詞需要分別統計其詞頻。
  3. 單詞按照詞頻和字典序排序:對於詞頻統計的結果,按照“次數按照降序排序,如果次數相同則按照鍵值的字母升序排序”的規則排序后輸出。

去除標點符號

首先對於輸入的單詞,需要先刪除標點符號,需要注意的是這些標點符號即使按照空格分割了整行子串,也是是緊挨在單詞之間的。因此刪除標點符號需要遍歷字符串,然后把題目要求去除的標點刪除。這里也可以使用 StringBuilder 類創建字符串,將英文字符依次組成一個字符串后返回。返回的使用 StringBuilder 類的 toString() 方法生成 String,然后使用 String 類的 toLowerCase() 方法將所有大寫字母轉換為小寫。此處封裝成方法供 main 方法調用:

public static String removePunctuation(String str){

      StringBuilder strbld = new StringBuilder();
      for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != '!' && str.charAt(i) != '.' && str.charAt(i) != ','
             && str.charAt(i) != ':' && str.charAt(i) != '*' && str.charAt(i) != '?') {
                  strbld.append(str.charAt(i));
	    }
      }
      return strbld.toString().toLowerCase();
}

統計詞頻

根據題意,我們需要用不定行輸入的方式輸入一整行,並且將整行文本分割成多個單詞。此處可以使用 String 類的 split() 方法,將單行輸入的字符串按照空格分割成多個單詞,並且用 removePunctuation()方法去除標點符號。注意到可能出現輸入空行,分割或去標點后出現空字符串的特殊情況,需要對這種情況進行額外的判斷。
統計詞頻可以封裝一個單詞類,單詞類有單詞和詞頻 2 個屬性,然后使用足夠大的數組或 List 進行存儲。也可以使用 Map 容器對 String 和 Integer 進行映射,此處使用 HashMap 進行詞頻的統計,使用 HashMap 的 put() 方法進行單詞詞頻的更新,若單詞還未被統計過就使用添加新單詞和詞頻為 1 的映射,若單詞使用 containsKey() 方法檢查已經存在,則先使用 get() 方法獲取當前詞頻,加一后再調用 put 方法。

Scanner sc = new Scanner(System.in);
Map<String,Integer> fre_map = new HashMap<String,Integer>();
while(true){
      String str = sc.nextLine();
      if(str.equals("!!!!!")) {
            break;
      }
      if (str != null && str.equals("")) {
            continue;
      }
      String[] words = str.split(" ");    //分割出單個單詞
      for(int i = 0; i < words.length; i++){
            String a_word = Main.removePunctuation(words[i]);    //獲取單個去除標點的單詞
            if(a_word == null || a_word.length() == 0) {
                  continue;
            }
            if(!fre_map.containsKey(a_word)) {    //單詞未被統計,建立新映射
                  fre_map.put(a_word, 1);
            }
            else{    //單詞已被統計過,更新數據
                  int num = fre_map.get(a_word) + 1;
        	  fre_map.put(a_word, num);
            }
      }
}

單詞排序

在程序的最后需要輸出詞頻前 10 的單詞,次數按照降序排序,如果次數相同則按照鍵值的字母升序排序。這個功能可以使用 HashMap 的 entrySet() 方法返回此 Map 所包含的映射關系的視圖,使用 List<Map.Entry<String, Integer>> 存儲之后用 Collections.sort() 方法進行排序。

//返回 fre_map 中所有映射關系的視圖,存儲入 1 個 ArrayList 中
List<Map.Entry<String, Integer>> fre_list = new ArrayList<Map.Entry<String, Integer>>(fre_map.entrySet());
Collections.sort(fre_list, new WordComparator());
        
System.out.println(fre_list.size());
int num = 0;
for (Map.Entry<String, Integer> e : fre_list) {
      System.out.println(e.getKey() + "=" + e.getValue());
      if(++num == 10) {
            break;
      }
}

為了支持 Collections.sort() 方法進行排序,需要寫一個實現了 Comparator 接口的 WordComparator 類,WordComparator 類的 compare() 界定了排序的規則。排序的規則為當單詞的詞頻相等時,使用 String 類的 compareTo() 方法實現字典序排序,否則調用 Integer 的 compareTo() 方法即可。

class WordComparator implements Comparator<Map.Entry<String, Integer>>{

      @Override
      public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
            if (o1.getValue().equals(o2.getValue()))    //2 個單詞詞頻相同,按照字典序進行排序
                  return o1.getKey().compareTo(o2.getKey());
	    else    //詞頻不同,按詞頻排序
                  return o2.getValue().compareTo(o1.getValue());
      }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM