UVa 12526 Cellphone Typing

题目分析

本题要求我们计算在使用特定自动补全规则的手机输入法时,输入字典中所有单词所需的平均击键次数。输入法的自动补全规则如下:

  1. 第一个字母必须手动输入
  2. 如果已输入的前缀在所有匹配的字典单词中下一个字母都相同,则系统自动输入该字母。
  3. 否则,系统等待用户手动输入。

关键观察

对于任意单词 w w w,其击键次数的计算方式为:

  • 第一个字母总是需要手动输入(计 1 1 1 次)
  • 对于后续的每个位置 i i i( i ≥ 1 i \geq 1 i≥1),如果前缀 w [ 0.. i − 1 ] w[0..i-1] w[0..i−1] 满足以下任一条件,则 w [ i ] w[i] w[i] 需要手动输入:
    • 该前缀是字典中某个完整单词的结尾
    • 该前缀在字典中有多个可能的下一个字母

例子分析

以字典 {hello, hell, heaven, goodbye} 为例:

  • hello:需要 3 3 3 次击键(hlo
  • hell:需要 2 2 2 次击键(hl
  • heaven:需要 2 2 2 次击键(ha
  • goodbye:需要 1 1 1 次击键(g

总计 8 8 8 次击键,平均 2.00 2.00 2.00。

数据结构选择

由于需要高效地处理字符串前缀查询,我们选择 Trie \texttt{Trie} Trie(字典树) 作为数据结构:

  • 每个节点存储 26 26 26 个子节点指针(对应小写字母)
  • 记录子节点数量
  • 标记当前节点是否是某个单词的结尾

算法步骤

  1. 构建 Trie \texttt{Trie} Trie:将所有单词插入到 Trie 中
  2. 计算击键次数 :对于每个单词:
    • 第一个字母总是手动输入(计数 + 1 +1 +1)
    • 对于后续每个字母,检查前一个字母对应的 Trie \texttt{Trie} Trie 节点:
      • 如果该节点是单词结尾 有多个子节点,则当前字母需要手动输入
  3. 计算平均值:总击键次数除以单词数量,保留两位小数

复杂度分析

  • 时间复杂度 : O ( L ) O(L) O(L),其中 L L L 是所有单词的总长度(不超过 1 0 6 10^6 106)
  • 空间复杂度 : O ( 26 × L ) O(26 \times L) O(26×L), Trie \texttt{Trie} Trie 节点的空间开销

代码实现

cpp 复制代码
// Cellphone Typing
// UVa ID: 12526
// Verdict: Accepted
// Submission Date: 2025-10-21
// UVa Run Time: 0.290s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net

#include <bits/stdc++.h>

using namespace std;

const int ALPHABET = 26;  // 小写字母数量

struct TrieNode {
    TrieNode* children[ALPHABET];  // 子节点指针数组
    int childCount;                 // 子节点数量
    bool isEndOfWord;               // 标记当前节点是否是单词结尾

    TrieNode() {
        memset(children, 0, sizeof(children));  // 初始化子节点为空
        childCount = 0;
        isEndOfWord = false;
    }
};

// 向 Trie 中插入单词
void insert(TrieNode* root, const string& word) {
    TrieNode* node = root;
    for (char ch : word) {
        int idx = ch - 'a';  // 计算字母对应的索引
        if (!node->children[idx]) {
            node->children[idx] = new TrieNode();
            node->childCount++;  // 新增子节点,计数增加
        }
        node = node->children[idx];
    }
    node->isEndOfWord = true;  // 标记单词结尾
}

// 计算输入单个单词所需的击键次数
int countKeystrokes(TrieNode* root, const string& word) {
    int keystrokes = 1;  // 第一个字母必须手动输入
    TrieNode* node = root->children[word[0] - 'a'];  // 移动到第一个字母对应的节点
    
    for (size_t i = 1; i < word.length(); i++) {
        // 如果当前节点是单词结尾或有多个子节点,需要手动输入下一个字母
        if (node->childCount > 1 || node->isEndOfWord) {
            keystrokes++;
        }
        node = node->children[word[i] - 'a'];  // 移动到下一个字母的节点
    }
    return keystrokes;
}

// 递归释放 Trie 内存
void clearTrie(TrieNode* node) {
    for (int i = 0; i < ALPHABET; i++) {
        if (node->children[i]) {
            clearTrie(node->children[i]);
            delete node->children[i];
        }
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);

    int N;
    while (cin >> N) {
        vector<string> words(N);
        TrieNode* root = new TrieNode();

        // 读取所有单词并构建 Trie
        for (int i = 0; i < N; i++) {
            cin >> words[i];
            insert(root, words[i]);
        }

        // 计算总击键次数
        int totalKeystrokes = 0;
        for (const string& w : words) {
            totalKeystrokes += countKeystrokes(root, w);
        }

        // 计算并输出平均值
        double average = static_cast<double>(totalKeystrokes) / N;
        cout << fixed << setprecision(2) << average << "\n";

        // 释放 Trie 内存
        clearTrie(root);
        delete root;
    }

    return 0;
}

该解法通过 Trie \texttt{Trie} Trie 高效地处理了前缀查询问题,能够在给定的约束条件下快速计算出平均击键次数。

相关推荐
一个不知名程序员www5 小时前
算法学习入门 --- 哈希表和unordered_map、unordered_set(C++)
c++·算法
Sarvartha5 小时前
C++ STL 栈的便捷使用
c++·算法
夏鹏今天学习了吗6 小时前
【LeetCode热题100(92/100)】多数元素
算法·leetcode·职场和发展
飞Link6 小时前
深度解析 MSER 最大稳定极值区域算法
人工智能·opencv·算法·计算机视觉
bubiyoushang8886 小时前
基于CLEAN算法的杂波抑制Matlab仿真实现
数据结构·算法·matlab
2401_894828127 小时前
从原理到实战:随机森林算法全解析(附 Python 完整代码)
开发语言·python·算法·随机森林
Remember_9937 小时前
【LeetCode精选算法】前缀和专题二
算法·哈希算法·散列表
源代码•宸7 小时前
Leetcode—509. 斐波那契数【简单】
经验分享·算法·leetcode·面试·golang·记忆化搜索·动规
博大世界8 小时前
matlab结构体数组定义
数据结构·算法
Loo国昌8 小时前
【LangChain1.0】第九阶段:文档处理工程 (LlamaIndex)
人工智能·后端·python·算法·langchain