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 高效地处理了前缀查询问题,能够在给定的约束条件下快速计算出平均击键次数。

相关推荐
kyle~4 小时前
C++---嵌套类型(Nested Types)封装与泛型的基石
开发语言·c++·算法
sali-tec4 小时前
C# 基于halcon的视觉工作流-章48-短路断路
开发语言·图像处理·人工智能·算法·计算机视觉
墨染点香4 小时前
LeetCode 刷题【128. 最长连续序列】
算法·leetcode·职场和发展
被AI抢饭碗的人4 小时前
算法题(240):最大食物链计数
算法
熬了夜的程序员5 小时前
【LeetCode】82. 删除排序链表中的重复元素 II
数据结构·算法·leetcode·链表·职场和发展·矩阵·深度优先
欧克小奥5 小时前
Floyd判圈算法(Floyd Cycle Detection Algorithm)
算法·floyd
熬了夜的程序员6 小时前
【LeetCode】83. 删除排序链表中的重复元素
算法·leetcode·链表
胖咕噜的稞达鸭6 小时前
AVL树手撕,超详细图文详解
c语言·开发语言·数据结构·c++·算法·visual studio
熊猫钓鱼>_>6 小时前
Rust语言特性深度解析:所有权、生命周期与模式匹配之我见
算法·rust·软件开发·函数·模式匹配·异步编程·质量工具