[CPE一星49題] UVA10008 - What's Cryptanalysis 題目解析與實作


編輯製作:
莊祺仁、蔡豐聲 

出品團隊: 中國醫藥大學 醫療資訊學系 程式俱樂部

 YT: https://youtu.be/lim8mc4xOqc

## 題目資訊

  • 題目名稱: What's Cryptanalysis
  • 編號: CPE10402, UVA10008 

## 題目解析

密碼翻譯(Cryptanalysis)是指把某個人寫的密文(Cryptographic writing)加以分解。這個程序通常會對密文訊息做統計分析。你的任務就是寫一個程式來對給定的密文進行簡單的字元統計分析。

## 輸入說明

  • 輸入的第 1 列有一個正整數 $n$,代表以下有多少列需要作分析的密文。

  • 接下來的 $n$ 列,每列含有 0 或多個字元(可能包含空格、標點符號與數字)。

## 輸出說明

  • 統計輸入中所有英文字母出現的頻率(大小寫視為相同,例如 A 與 a 算同一字元)。

  • 每列包含一個大寫字元 (A~Z) 和一個正整數(代表該字母出現的次數),兩者以空格分開。

  • 排序規則:
  1. 按照字元出現的次數由大到小排列(降序)。
  2. 如果有 2 個以上的字元出現次數相同,則按照字母順序由小到大排列(升序,如 A 在 H 之前)。
  • 注意:若某一字母未在輸入中出現過,則不應出現在輸出中。

## 範例測試

  • 輸入:
               3                                                 
               This is a test.                              
               Count me 1 2 3 4 5.                     
               Wow!!!! Is this question easy?    
  • 輸出:
                S 7 
                T 6 
                I 5  
                E 4 
                O 3  
                A 2 
                H 2 
                N 2 
                U 2 
                W 2  
                C 1 
                M 1 
                Q 1 
                Y 1 

## 解題思路

  • 字串處理常用方法

  1. char.upper():將字元轉換為大寫,方便不分大小寫合併計數。
  2. char.isalpha():檢查字元是否為英文字母,可用來過濾標點符號、數字與空格。

  • 字典(Dictionary)計數
  1. 利用字典結構儲存 {字母: 出現次數}。
  2. 當讀到字母時,若已在字典中則累加 +1,若尚未出現則初始化設為 1(亦可使用 dict.get(key, 0) + 1)。
  • 多條件自訂排序(sorted + lambda)
  1. 使用 dict.items() 取出所有 (key, value)(即 (字母, 次數))的鍵值對。
  2. 透過 lambda item: (-item[1], item[0]) 設定複合排序鍵:
        (i) -item[1]:次數加上負號,使出現次數呈現由大到小(降序)。
        (ii) item[0]:當次數相同時,依字母本身順序呈現由小到大(升序)。

## 實作程式碼 (Python)

# 1. 讀取整數 n
n = int(input())

# 初始化一個字典,用來記錄每個字母出現的次數
total = {}

# 2. 讀取 n 行輸入字串
for _ in range(n):
    str_a = input()  # 讀取一行字串
    # 逐字走訪字串中的每個字元
    for char in str_a:
        char = char.upper()  # 將字元轉為大寫,實現不分大小寫統計
        if char.isalpha():   # 檢查是否為英文字母 (過濾掉標點符號、數字與空格)
            if char in total:
                total[char] += 1  # 若字母已存在字典中,累加計數
            else:
                total[char] = 1   # 若字母首次出現,初始化計數為 1

# 3. 對統計結果進行排序並印出:
#    -item[1]: 依出現次數由大到小排序 (降序)
#    item[0] : 若次數相同,則依字母 A-Z 順序排序 (升序)
for i in sorted(total.items(), key=lambda item: (-item[1], item[0])):
    print(f"{i[0]} {i[1]}")  # 印出字母與其對應的出現次數