[POJ] #1003# 487-3279 : 桶排序/字典树(Trie树)/快速排序

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POJ] #1003# 487-3279 : 桶排序/字典树(Trie树)/快速排序相关的知识,希望对你有一定的参考价值。

一. 题目

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

 

二. 题意

  1.电话簿上的电话号码为了方便记忆,并非全用数字表示,有些用字母表示或用 “ - ” 符号分割

  2.字母与数字之间存在一定的映射关系,“ - ” 没有实际意义

  3. 通过转换后得到统一标准的电话号码,其构成为"xxx-xxxx", 总共由八位字符(七位数字和一个"-")符号构成

  5. 现在给定一个电话清单,从中找出重复的电话号码

 

三. 分析

  1. 算法核心: 三种解决方法

    1.1 桶排序

    1.2 字典树(Trie树)

    1.3 快速排序

  2. 实现细节:

    2.1 桶排序

      2.1.1 桶的大小为七位数的上限(10000000)

      2.1.2 每个桶存储对应7位数的电话号码出现的次数

      2.1.3 将电话号码转换为7位数,递增对应该七位数的桶元素的值

      2.1.4 遍历所有桶,得到和输出大于1的所有桶元素

      2.1.5 小细节: 字符到数的转换,输出格式的正确转换

    2.2 字典树(Trie树)

      2.2.1 建立Trie树: 用静态数组存储每个node,  简化代码实现

      2.2.2 遍历所有输入电话号码,转换为数字,将该数字插入Trie树

      2.2.3 每插入一个完整电话号码,在其最后插入的node中设置两个标记:出现次数 和 完整电话号码的结束标记

      2.2.4 深度遍历(dfs)Trie树, 输出所有出现次数大于1的完整电话号码

      2.2.5 Trie树的所有child构成为从左到右(0 - 9),遍历的顺序也是如此,从而保证了电话号码的输出顺序也是从小到大

    2.3 快速排序

      2.3.1 用一个二维字符数组存储所有的电话号码

      2.3.2 对该数组进行快速排序

      2.3.3 遍历该有序数组,顺序输出大于1的所有电话号码

      2.3.4 个人实现算法的宗旨是尽量少用库,能实现的尽量自己实现

        2.3.4.1 对于此题,发现如果用自己实现的快速排序,发现会超时

          2.3.4.2 换成库的qsort则可以通过

        2.3.4.3 分析发现实际上库对于qsort做了很多的优化,并非基本的快排,有时间可以研究一下

        2.3.4.4 两个qsort优化的参考文档:

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

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

四. 题解

4.1 桶排序

 1 #include <stdio.h>
 2 
 3 #define PHONE_NUMBER 256
 4 #define MAX_NUMBER 10000000
 5 #define BASE_NUMBER 1000000
 6 #define LENGTH_NUMBER 8
 7 #define MAP_SIZE (‘Z‘ - ‘A‘ + 1)
 8 int map_num[MAP_SIZE] = {2, 2, 2, 3, 3, 3, 4, 4, 4,
 9                          5, 5, 5, 6, 6, 6, 7, -1, 7,
10                          7, 8, 8, 8, 9, 9, 9, -1};
11 int bucket[MAX_NUMBER];
12 
13 int main()
14 {
15     int i = 0, j = 0, count = 0, nums = 0;
16 
17     scanf("%d\n", &count);
18     for (j = 0; j < count; j++) {
19         char phone_number[PHONE_NUMBER];
20         int tmp = 0;
21         
22         scanf("%s\n", phone_number);
23         
24         for (i = 0; phone_number[i] != \0; i++) {
25             if (- == phone_number[i]) continue;
26             tmp = tmp * 10 + 
27                  ((phone_number[i] >= A && phone_number[i] <= Z) ? 
28                  map_num[phone_number[i] - A] : phone_number[i] - 0);
29         }
30         bucket[tmp]++;
31     }
32 
33     for (i = 0; i < MAX_NUMBER; i++) {
34         int b_tmp, base_number = BASE_NUMBER;
35 
36         if (bucket[i] < 2) continue;
37 
38         b_tmp = i;
39         nums++;
40 
41         for (j = 0; j < LENGTH_NUMBER; j++) {
42             if (3 == j) { printf("-"); continue; }
43             printf("%d", b_tmp / base_number);
44             b_tmp %= base_number;
45             base_number /= 10;
46         }
47         printf(" %d\n", bucket[i]);
48     }
49 
50     if (0 == nums) printf("No duplicates.\n");
51 
52     return 0;
53 }

 

 

 4.2 字典树(Trie树)

 1 #include <stdio.h>
 2 
 3 #define BASE_NUMBER 1000000
 4 #define MAP_SIZE (‘Z‘ - ‘A‘ + 1)
 5 #define TRIE_CHILD_CNTS 10
 6 #define PHONE_NUMBER 256
 7 #define PHONE_NUMBER_LENGTH 7
 8 #define BASE_NUMBER 1000000
 9 
10 int map_num[MAP_SIZE] = {2, 2, 2, 3, 3, 3, 4, 4, 4,
11                          5, 5, 5, 6, 6, 6, 7, -1, 7,
12                          7, 8, 8, 8, 9, 9, 9, -1};
13 int tree_index = 0;
14 int is_duplicated = 0;
15 
16 typedef struct Trie {
17     int is_word;
18     int word_cnts;
19     struct Trie* childs[TRIE_CHILD_CNTS];
20 } trie_tree_t;
21 
22 trie_tree_t trie_nodes[BASE_NUMBER];
23 
24 void new_trie_tree(int index) {
25     int i;
26     trie_nodes[index].is_word = 0;
27     trie_nodes[index].word_cnts = 0;
28     for (i = 0; i < TRIE_CHILD_CNTS; i++) trie_nodes[index].childs[i] = NULL;
29 }
30 
31 void add_trie_node(int num) {
32     int i, j, base_number = BASE_NUMBER;
33     trie_tree_t* tree = &trie_nodes[0];
34 
35     for (i = 0; i < PHONE_NUMBER_LENGTH; i++) {
36         j = num / base_number;
37         num %= base_number;
38         base_number /= 10;
39         if (NULL == tree->childs[j]) {
40             new_trie_tree(++tree_index);
41             tree->childs[j] = &trie_nodes[tree_index]; 
42         }
43         tree = tree->childs[j];
44     }
45 
46     tree->is_word = 1;
47     tree->word_cnts++;
48 }
49 
50 void dfs(int phone_number[PHONE_NUMBER_LENGTH], int number_index, trie_tree_t *tree_p)
51 {
52     int i;
53     if (tree_p->is_word && 1 < tree_p->word_cnts) {
54         for (i = 0; i < PHONE_NUMBER_LENGTH; i++) {
55             if (3 == i) printf("-");
56 
57             printf("%d", phone_number[i]);
58         }
59 
60         printf(" %d\n", tree_p->word_cnts);
61         is_duplicated = 1;
62     }
63 
64     for (i = 0; i < TRIE_CHILD_CNTS; i++) {
65         if (tree_p->childs[i] && number_index < PHONE_NUMBER_LENGTH) {
66             phone_number[number_index] = i;
67             dfs(phone_number, number_index + 1, tree_p->childs[i]);
68         }
69     }
70 }
71 
72 int main()
73 {
74     int i = 0, j = 0, tmp = 0, count = 0;
75     int number[PHONE_NUMBER_LENGTH];
76 
77     scanf("%d\n", &count);
78     for (j = 0; j < count; j++) {
79         char phone_number[PHONE_NUMBER];        
80         int tmp = 0;
81         scanf("%s\n", phone_number);
82         
83         for (i = 0; phone_number[i] != \0; i++) {
84             if (- == phone_number[i]) continue;
85             tmp = tmp * 10 + 
86                  ((phone_number[i] >= A && phone_number[i] <= Z) ? 
87                  map_num[phone_number[i] - A] : phone_number[i] - 0);
88         }
89 
90         add_trie_node(tmp);
91     }
92 
93     dfs(number, 0, &trie_nodes[0]);
94 
95     if (0 == is_duplicated) printf("No duplicates.\n");
96 
97     return 0;
98 }

 

4.3 快速排序

  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <string.h>
  4 
  5 #define PHONE_NUMBER 256
  6 #define MAX_NUMBERS 100000
  7 #define LENGTH_NUMBER 9
  8 #define MAP_SIZE (‘Z‘ - ‘A‘ + 1)
  9 #define SEP_INDEX 3
 10 
 11 #define CUSTOM 0
 12 #define USING_POINTER_FOR_COMPARE 0
 13 
 14 char map_num[MAP_SIZE] = {2, 2, 2, 3, 3, 3, 4, 4, 4,
 15                          5, 5, 5, 6, 6, 6, 7, -1, 7,
 16                          7, 8, 8, 8, 9, 9, 9, -1};
 17 
 18 char numbers[MAX_NUMBERS][LENGTH_NUMBER];
 19 
 20 #if USING_POINTER_FOR_COMPARE
 21 char *p_numbers[MAX_NUMBERS];
 22 #endif
 23 
 24 int is_duplicate = 0;
 25 
 26 int mystrcmp(const char *str1, const char *str2)
 27 {
 28     while (*str1 == *str2) {
 29         if (*str1 == \0) return 0;
 30         str1++; str2++;
 31     }
 32 
 33     return *str1 - *str2;
 34 }
 35 
 36 #if CUSTOM
 37 
 38 #if USING_POINTER_FOR_COMPARE
 39 
 40 void quicksort(char *A[], int left, int right, int(*func)(const char*, const char*)) {
 41     int i = left, j = right;
 42     char *t, *tmp;
 43     tmp = A[i];
 44     
 45     if (i > j) return;
 46 
 47     while (i != j) {
 48         while (func(tmp, A[j]) <= 0 && i < j) j--;
 49         while (func(A[i], tmp) <= 0 && i < j) i++;
 50 
 51         if (i < j) {
 52             t = A[i];
 53             A[i] = A[j];
 54             A[j] = t;
 55         }
 56     }
 57     A[left] = A[i];
 58     A[i] = tmp;
 59 
 60     quicksort(A, left, i - 1, func);
 61     quicksort(A, i + 1, right, func);
 62 }
 63 
 64 #else
 65 
 66 void mystrcpy(char *str1, const char *str2)
 67 {
 68     while (*str2 != \0) {
 69         *str1 = *str2;
 70         str1++; str2++;
 71     }
 72 
 73     *str1 = \0;
 74 }
 75 
 76 void quicksort(char A[][LENGTH_NUMBER], int left, int right, int(*func)(const char*, const char*)) {
 77     int i = left, j = right;
 78     char t[LENGTH_NUMBER], tmp[LENGTH_NUMBER];
 79     mystrcpy(tmp, A[i]);
 80     
 81     if (i > j) return;
 82 
 83     while (i != j) {
 84         while (func(tmp, A[j]) <= 0 && i < j) j--;
 85         while (func(A[i], tmp) <= 0 && i < j) i++;
 86 
 87         if (i < j) {
 88             mystrcpy(t, A[i]);
 89             mystrcpy(A[i], A[j]);
 90             mystrcpy(A[j], t);
 91         }
 92     }
 93     mystrcpy(A[left], A[i]);
 94     mystrcpy(A[i], tmp);
 95 
 96     quicksort(A, left, i - 1, func);
 97     quicksort(A, i + 1, right, func);
 98 }
 99 
100 #endif
101 
102 #endif
103 
104 int sort_function(const void *a,const void *b)  
105 { 
106     return(strcmp((char*)a,(char*)b));  
107 }   
108 
109 int main()
110 {
111     int i = 0, j = 0, count = 0, nums = 1, number_index = 0;
112 
113     scanf("%d\n", &count);
114     for (j = 0; j < count; j++) {
115         char phone_number[PHONE_NUMBER];
116         
117         scanf("%s\n", phone_number);
118         
119         for (i = 0; phone_number[i] != \0; i++) {
120             if (- == phone_number[i]) continue;
121             if (SEP_INDEX == number_index) numbers[j][number_index++] = -;            
122             numbers[j][number_index++] = ((phone_number[i] >= A && phone_number[i] <= Z) ? 
123                                         map_num[phone_number[i] - A] : phone_number[i]);
124         }
125         number_index = 0;
126 
127 #if USING_POINTER_FOR_COMPARE
128         p_numbers[j] = numbers[j];
129 #endif
130 
131     }
132 
133 #if CUSTOM
134     quicksort(p_numbers, 0, count - 1, mystrcmp);
135 
136 #if USING_POINTER_FOR_COMPARE
137 
138     for (j = 0; j < count - 1; j++) {
139         if (0 == mystrcmp(p_numbers[j], p_numbers[j + 1])) {
140             is_duplicate = 1;
141             nums++;
142         } else {
143             if (1 < nums) printf("%s %d\n", p_numbers[j], nums);
144             nums  = 1;
145         }
146     }
147 
148     if (1 < nums) printf("%s %d\n", p_numbers[j], nums);
149 
150 #else
151 
152     for (j = 0; j < count - 1; j++) {
153         if (0 == mystrcmp(numbers[j], numbers[j + 1])) {
154             is_duplicate = 1;
155             nums++;
156         } else {
157             if (1 < nums) printf("%s %d\n", numbers[j], nums);
158             nums  = 1;
159         }
160     }
161 
162     if (1 < nums) printf("%s %d\n", numbers[j], nums);
163 
164 #endif
165 
166     
167 #else
168 
169     qsort(numbers, count, LENGTH_NUMBER, sort_function);
170 
171     for (j = 0; j < count - 1; j++) {
172         if (0 == mystrcmp(numbers[j], numbers[j + 1])) {
173             is_duplicate = 1;
174             nums++;
175         } else {
176             if (1 < nums) printf("%s %d\n", numbers[j], nums);
177             nums  = 1;
178         }
179     }
180 
181     if (1 < nums) printf("%s %d\n", numbers[j], nums);
182 
183 #endif
184 
185     if (0 == is_duplicate) printf("No duplicates.\n");
186 
187     return 0;
188 }

 

以上是关于[POJ] #1003# 487-3279 : 桶排序/字典树(Trie树)/快速排序的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1002 487-3279

poj1002-487-3279

487-3279[POJ1002]

POJ 1002 487-3279

[poj 1002]487-3279

POJ 1002 487-3279(map映照容器的使用)