一. 题目

487-3279
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 274040   Accepted: 48891

Description

Businesses like to have memorable telephone numbers. One way to make a telephone number memorable is to have it spell a memorable word or phrase. For example, you can call the University of Waterloo by dialing the memorable TUT-GLOP. Sometimes only part of the number is used to spell a word. When you get back to your hotel tonight you can order a pizza from Gino's by dialing 310-GINO. Another way to make a telephone number memorable is to group the digits in a memorable way. You could order your pizza from Pizza Hut by calling their ``three tens'' number 3-10-10-10.

The standard form of a telephone number is seven decimal digits with
a hyphen between the third and fourth digits (e.g. 888-1200). The
keypad of a phone supplies the mapping of letters to numbers, as
follows:

A, B, and C map to 2

D, E, and F map to 3

G, H, and I map to 4

J, K, and L map to 5

M, N, and O map to 6

P, R, and S map to 7

T, U, and V map to 8

W, X, and Y map to 9

There is no mapping for Q or Z. Hyphens are not dialed, and can be
added and removed as necessary. The standard form of TUT-GLOP is
888-4567, the standard form of 310-GINO is 310-4466, and the standard
form of 3-10-10-10 is 310-1010.

Two telephone numbers are equivalent if they have the same standard form. (They dial the same number.)

Your company is compiling a directory of telephone numbers from
local businesses. As part of the quality control process you want to
check that no two (or more) businesses in the directory have the same
telephone number.

Input

The
input will consist of one case. The first line of the input specifies
the number of telephone numbers in the directory (up to 100,000) as a
positive integer alone on the line. The remaining lines list the
telephone numbers in the directory, with each number alone on a line.
Each telephone number consists of a string composed of decimal digits,
uppercase letters (excluding Q and Z) and hyphens. Exactly seven of the
characters in the string will be digits or letters.

Output

Generate
a line of output for each telephone number that appears more than once
in any form. The line should give the telephone number in standard form,
followed by a space, followed by the number of times the telephone
number appears in the directory. Arrange the output lines by telephone
number in ascending lexicographical order. If there are no duplicates in
the input print the line:

No duplicates.

Sample Input

12
4873279
ITS-EASY
888-4567
3-10-10-10
888-GLOP
TUT-GLOP
967-11-11
310-GINO
F101010
888-1200
-4-8-7-3-2-7-9-
487-3279

Sample Output

310-1010 2
487-3279 4
888-4567 3

Source

 

二. 题意

  • 电话簿上的电话号码为了方便记忆,并非全用数字表示,有些用字母表示或用 “ - ” 符号分割
  • 字母与数字之间存在一定的映射关系,“ - ” 没有实际意义
  • 通过转换后得到统一标准的电话号码,其构成为"xxx-xxxx", 总共由八位字符(七位数字和一个"-")符号构成
  • 现在给定一个电话清单,从中找出重复的电话号码

三. 分析

  • 算法核心: 三种解决方法

    • 桶排序
    • 字典树(Trie树)
    • 快速排序
  • 实现细节:
    • 桶排序

      • 桶的大小为七位数的上限(10000000)
      • 每个桶存储对应7位数的电话号码出现的次数
      • 将电话号码转换为7位数,递增对应该七位数的桶元素的值
      • 遍历所有桶,得到和输出大于1的所有桶元素
      • 小细节: 字符到数的转换,输出格式的正确转换
    • 字典树(Trie树)
      • 建立Trie树: 用静态数组存储每个node,  简化代码实现
      • 遍历所有输入电话号码,转换为数字,将该数字插入Trie树
      • 每插入一个完整电话号码,在其最后插入的node中设置两个标记:出现次数 和 完整电话号码的结束标记
      • 深度遍历(dfs)Trie树, 输出所有出现次数大于1的完整电话号码
      • Trie树的所有child构成为从左到右(0 - 9),遍历的顺序也是如此,从而保证了电话号码的输出顺序也是从小到大
    • 快速排序
      • 用一个二维字符数组存储所有的电话号码
      • 对该数组进行快速排序
      • 遍历该有序数组,顺序输出大于1的所有电话号码
      • 个人实现算法的宗旨是尽量少用库,能实现的尽量自己实现
        • 对于此题,发现如果用自己实现的快速排序,发现会超时
        • 换成库的qsort则可以通过
        • 分析发现实际上库对于qsort做了很多的优化,并非基本的快排,有时间可以研究一下
        • 两个qsort优化的参考文档:

           http://blog.chinaunix.net/uid-25510439-id-275436.html

           http://blog.csdn.net/insistgogo/article/details/7785038

四. 题解

  • 桶排序
 #include <stdio.h>

 #define PHONE_NUMBER 256
#define MAX_NUMBER 10000000
#define BASE_NUMBER 1000000
#define LENGTH_NUMBER 8
#define MAP_SIZE ('Z' - 'A' + 1)
int map_num[MAP_SIZE] = {, , , , , , , , ,
, , , , , , , -, ,
, , , , , , , -};
int bucket[MAX_NUMBER]; int main()
{
int i = , j = , count = , nums = ; scanf("%d\n", &count);
for (j = ; j < count; j++) {
char phone_number[PHONE_NUMBER];
int tmp = ; scanf("%s\n", phone_number); for (i = ; phone_number[i] != '\0'; i++) {
if ('-' == phone_number[i]) continue;
tmp = tmp * +
((phone_number[i] >= 'A' && phone_number[i] <= 'Z') ?
map_num[phone_number[i] - 'A'] : phone_number[i] - '');
}
bucket[tmp]++;
} for (i = ; i < MAX_NUMBER; i++) {
int b_tmp, base_number = BASE_NUMBER; if (bucket[i] < ) continue; b_tmp = i;
nums++; for (j = ; j < LENGTH_NUMBER; j++) {
if ( == j) { printf("-"); continue; }
printf("%d", b_tmp / base_number);
b_tmp %= base_number;
base_number /= ;
}
printf(" %d\n", bucket[i]);
} if ( == nums) printf("No duplicates.\n"); return ;
}
  • 字典树(Trie树)
 #include <stdio.h>

 #define BASE_NUMBER 1000000
#define MAP_SIZE ('Z' - 'A' + 1)
#define TRIE_CHILD_CNTS 10
#define PHONE_NUMBER 256
#define PHONE_NUMBER_LENGTH 7
#define BASE_NUMBER 1000000 int map_num[MAP_SIZE] = {, , , , , , , , ,
, , , , , , , -, ,
, , , , , , , -};
int tree_index = ;
int is_duplicated = ; typedef struct Trie {
int is_word;
int word_cnts;
struct Trie* childs[TRIE_CHILD_CNTS];
} trie_tree_t; trie_tree_t trie_nodes[BASE_NUMBER]; void new_trie_tree(int index) {
int i;
trie_nodes[index].is_word = ;
trie_nodes[index].word_cnts = ;
for (i = ; i < TRIE_CHILD_CNTS; i++) trie_nodes[index].childs[i] = NULL;
} void add_trie_node(int num) {
int i, j, base_number = BASE_NUMBER;
trie_tree_t* tree = &trie_nodes[]; for (i = ; i < PHONE_NUMBER_LENGTH; i++) {
j = num / base_number;
num %= base_number;
base_number /= ;
if (NULL == tree->childs[j]) {
new_trie_tree(++tree_index);
tree->childs[j] = &trie_nodes[tree_index];
}
tree = tree->childs[j];
} tree->is_word = ;
tree->word_cnts++;
} void dfs(int phone_number[PHONE_NUMBER_LENGTH], int number_index, trie_tree_t *tree_p)
{
int i;
if (tree_p->is_word && < tree_p->word_cnts) {
for (i = ; i < PHONE_NUMBER_LENGTH; i++) {
if ( == i) printf("-"); printf("%d", phone_number[i]);
} printf(" %d\n", tree_p->word_cnts);
is_duplicated = ;
} for (i = ; i < TRIE_CHILD_CNTS; i++) {
if (tree_p->childs[i] && number_index < PHONE_NUMBER_LENGTH) {
phone_number[number_index] = i;
dfs(phone_number, number_index + , tree_p->childs[i]);
}
}
} int main()
{
int i = , j = , tmp = , count = ;
int number[PHONE_NUMBER_LENGTH]; scanf("%d\n", &count);
for (j = ; j < count; j++) {
char phone_number[PHONE_NUMBER];
int tmp = ;
scanf("%s\n", phone_number); for (i = ; phone_number[i] != '\0'; i++) {
if ('-' == phone_number[i]) continue;
tmp = tmp * +
((phone_number[i] >= 'A' && phone_number[i] <= 'Z') ?
map_num[phone_number[i] - 'A'] : phone_number[i] - '');
} add_trie_node(tmp);
} dfs(number, , &trie_nodes[]); if ( == is_duplicated) printf("No duplicates.\n"); return ;
}
  • 快速排序
 #include <stdio.h>
#include <stdlib.h>
#include <string.h> #define PHONE_NUMBER 256
#define MAX_NUMBERS 100000
#define LENGTH_NUMBER 9
#define MAP_SIZE ('Z' - 'A' + 1)
#define SEP_INDEX 3 #define CUSTOM 0
#define USING_POINTER_FOR_COMPARE 0 char map_num[MAP_SIZE] = {'', '', '', '', '', '', '', '', '',
'', '', '', '', '', '', '', '-1', '',
'', '', '', '', '', '', '', '-1'}; char numbers[MAX_NUMBERS][LENGTH_NUMBER]; #if USING_POINTER_FOR_COMPARE
char *p_numbers[MAX_NUMBERS];
#endif int is_duplicate = ; int mystrcmp(const char *str1, const char *str2)
{
while (*str1 == *str2) {
if (*str1 == '\0') return ;
str1++; str2++;
} return *str1 - *str2;
} #if CUSTOM #if USING_POINTER_FOR_COMPARE void quicksort(char *A[], int left, int right, int(*func)(const char*, const char*)) {
int i = left, j = right;
char *t, *tmp;
tmp = A[i]; if (i > j) return; while (i != j) {
while (func(tmp, A[j]) <= && i < j) j--;
while (func(A[i], tmp) <= && i < j) i++; if (i < j) {
t = A[i];
A[i] = A[j];
A[j] = t;
}
}
A[left] = A[i];
A[i] = tmp; quicksort(A, left, i - , func);
quicksort(A, i + , right, func);
} #else void mystrcpy(char *str1, const char *str2)
{
while (*str2 != '\0') {
*str1 = *str2;
str1++; str2++;
} *str1 = '\0';
} void quicksort(char A[][LENGTH_NUMBER], int left, int right, int(*func)(const char*, const char*)) {
int i = left, j = right;
char t[LENGTH_NUMBER], tmp[LENGTH_NUMBER];
mystrcpy(tmp, A[i]); if (i > j) return; while (i != j) {
while (func(tmp, A[j]) <= && i < j) j--;
while (func(A[i], tmp) <= && i < j) i++; if (i < j) {
mystrcpy(t, A[i]);
mystrcpy(A[i], A[j]);
mystrcpy(A[j], t);
}
}
mystrcpy(A[left], A[i]);
mystrcpy(A[i], tmp); quicksort(A, left, i - , func);
quicksort(A, i + , right, func);
} #endif #endif int sort_function(const void *a,const void *b)
{
return(strcmp((char*)a,(char*)b));
} int main()
{
int i = , j = , count = , nums = , number_index = ; scanf("%d\n", &count);
for (j = ; j < count; j++) {
char phone_number[PHONE_NUMBER]; scanf("%s\n", phone_number); for (i = ; phone_number[i] != '\0'; i++) {
if ('-' == phone_number[i]) continue;
if (SEP_INDEX == number_index) numbers[j][number_index++] = '-';
numbers[j][number_index++] = ((phone_number[i] >= 'A' && phone_number[i] <= 'Z') ?
map_num[phone_number[i] - 'A'] : phone_number[i]);
}
number_index = ; #if USING_POINTER_FOR_COMPARE
p_numbers[j] = numbers[j];
#endif } #if CUSTOM
quicksort(p_numbers, , count - , mystrcmp); #if USING_POINTER_FOR_COMPARE for (j = ; j < count - ; j++) {
if ( == mystrcmp(p_numbers[j], p_numbers[j + ])) {
is_duplicate = ;
nums++;
} else {
if ( < nums) printf("%s %d\n", p_numbers[j], nums);
nums = ;
}
} if ( < nums) printf("%s %d\n", p_numbers[j], nums); #else for (j = ; j < count - ; j++) {
if ( == mystrcmp(numbers[j], numbers[j + ])) {
is_duplicate = ;
nums++;
} else {
if ( < nums) printf("%s %d\n", numbers[j], nums);
nums = ;
}
} if ( < nums) printf("%s %d\n", numbers[j], nums); #endif #else qsort(numbers, count, LENGTH_NUMBER, sort_function); for (j = ; j < count - ; j++) {
if ( == mystrcmp(numbers[j], numbers[j + ])) {
is_duplicate = ;
nums++;
} else {
if ( < nums) printf("%s %d\n", numbers[j], nums);
nums = ;
}
} if ( < nums) printf("%s %d\n", numbers[j], nums); #endif if ( == is_duplicate) printf("No duplicates.\n"); return ;
}

[POJ] #1002# 487-3279 : 桶排序/字典树(Trie树)/快速排序的更多相关文章

  1. 字典树(Trie树)的实现及应用

    >>字典树的概念 Trie树,又称字典树,单词查找树或者前缀树,是一种用于快速检索的多叉树结构,如英文字母的字典树是一个26叉树,数字的字典树是一个10叉树.与二叉查找树不同,Trie树的 ...

  2. Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结

    Atitit 常见的树形结构 红黑树  二叉树   B树 B+树  Trie树 attilax理解与总结 1.1. 树形结构-- 一对多的关系1 1.2. 树的相关术语: 1 1.3. 常见的树形结构 ...

  3. 洛谷$P4585\ [FJOI2015]$火星商店问题 线段树+$trie$树

    正解:线段树+$trie$树 解题报告: 传送门$QwQ$ $umm$题目有点儿长我先写下题目大意趴$QwQ$,就说有$n$个初始均为空的集合和$m$次操作,每次操作为向某个集合内加入一个数$x$,或 ...

  4. luoguP6623 [省选联考 2020 A 卷] 树(trie树)

    luoguP6623 [省选联考 2020 A 卷] 树(trie树) Luogu 题外话: ...想不出来啥好说的了. 我认识的人基本都切这道题了. 就我只会10分暴力. 我是傻逼. 题解时间 先不 ...

  5. 字典树 trie树 学习

    一字典树 字典树,又称单词查找树,Trie树,是一种树形结构,哈希表的一个变种   二.性质 根节点不包含字符,除根节点以外的每一个节点都只包含一个字符: 从根节点到某一节点,路径上经过的字符串连接起 ...

  6. 【字符串算法】字典树(Trie树)

    什么是字典树 基本概念 字典树,又称为单词查找树或Tire树,是一种树形结构,它是一种哈希树的变种,用于存储字符串及其相关信息. 基本性质 1.根节点不包含字符,除根节点外的每一个子节点都包含一个字符 ...

  7. [转载]字典树(trie树)、后缀树

    (1)字典树(Trie树) Trie是个简单但实用的数据结构,通常用于实现字典查询.我们做即时响应用户输入的AJAX搜索框时,就是Trie开始.本质上,Trie是一颗存储多个字符串的树.相邻节点间的边 ...

  8. Luogu P2922 [USACO08DEC]秘密消息Secret Message 字典树 Trie树

    本来想找\(01Trie\)的结果找到了一堆字典树水题...算了算了当水个提交量好了. 直接插入模式串,维护一个\(Trie\)树的子树\(sum\)大小,求解每一个文本串匹配时走过的链上匹配数和终点 ...

  9. 字典树 Trie树

    什么是Trie树? 形如 其中从根节点到红色节点的路径上的字母所连成的字符串即为一个Trie树上所存的字符串. 比如,这个trie树上有ab,abc,bd,dda这些字符串. 至于怎么构建和查找或添加 ...

随机推荐

  1. 51nod 1092 回文字符串 (dp)

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1092 这个题是poj-3280的简化版,这里只可以增加字符,设 dp[i ...

  2. 【HDOJ】3208 Integer’s Power

    1. 题目描述定义如下函数$f(x)$:对于任意整数$y$,找到满足$x^k = y$同时$x$最小并的$k$值.所求为区间$[a, b]$的数代入$f$的累加和,即\[\sum_{x=a}^{b} ...

  3. js 监听监键盘动作

    浏览器firefoxfunctionoperamicrosoftmozilla 转载自:http://geelong.javaeye.com/blog/810054 主要分四个部分第一部分:浏览器的按 ...

  4. Hibernate HQL注入攻击入门

    SQL注入是一种大家非常熟悉的攻击方式,目前网络上有大量存在注入漏洞的DBMS(如MySQL,Oracle,MSSQL等).但是,我在网络上找不到针对Hibernate查询语言的相关资源.因此本文总结 ...

  5. CSS选择符类型

    一.标签选择符:针对某一类标签,可以以标签作为选择符 <style type="text/css"> p{color:#F00; font-size:36px;} &l ...

  6. Qt之QHeaderView自定义排序(获取正确的QModelIndex)

    简述 前几节中分享过关于自定义排序的功能,貌似我们之前的内容已经可以很好地解决排序问题了,但是,会由此引发一些很难发现的问题...比如:获取QModelIndex索引错误. 下面,我们先来实现一个整行 ...

  7. hdu 4647 Another Graph Game

    题意: 有N个点,M条边. 点有权值, 边有权值. Alice, Bob 分别选点. 如果一条边的两个顶点被同一个人选了, 那么能获得该权值.问 Alice - Bob? 链接:http://acm. ...

  8. vs2008破解方法

    前提条件:测试操作系统WIN7 1,解压缩镜像文件 2,找到文件:Setup\setup.sdb,用记事本打开: 3,找到以下项: [Product Key]XPWKC7X98VKQDGM3QWYVG ...

  9. 谷歌浏览器如何设置可以解决Ajax跨域问题?

    Ajax本身是不支持跨域的,跨域问题其实很简单,通过浏览器的相应设置可以完成两个不同的服务器或两个不同服务下的项目互相访问.希望大家给予评价及投票. 方法/步骤   首先谷歌快捷方式上右击,在下拉列表 ...

  10. Readonly与const初识

    对于readonly和const,很多人无法具体区分,不清楚它们的具体使用场合:现在我们分析它们之间的区别和使用场合. const是一个编译期常量:const只能用于修饰基元类型.枚举类型或者字符串类 ...