POJ 1002 解题分析
解题分析
题目非常简单,可以分为以下三个步骤:
-
对输入进行翻译(格式化)使之成为标准的电话号码格式XXX-XXXX
-
统计电话号码的出现次数
-
按照字典序升序输出重复出现的电话号码及其重复次数,没有重复的输出"No duplicates."
第一个步骤没有什么难度,遇到"-"就跳过,遇到数字直接减"0"就可以了,遇到字母就按照题目中的规则进行Map。
第二个步骤就出现分歧了,大约有以下三种可能:
-
直接把解析后的电话号码插入到序列容器里,等到扫描完毕后对序列进行排序,然后统计并输出重复的电话号码
-
使用哈希表存放包含电话号码和出现次数的一个数据结构,然后排序输出
-
使用二叉查找树存放包含电话号码和出现次数的一个数据结构,然后遍历并输出
排序法
第一种方法最为直接,但是后来我从论坛里看到很多这么做的人都超时了。
个人感觉这种方法不会超时,不知道为什么那么多人卡住了。
使用数组作为容器,快速排序作为排序方法,分析一下时间复杂性:
假设每个输入的电话号码的长度不超过\(m\),一共有\(n\)个电话号码
则解析一个电话号码的时间为\(O(m)\),插入的时间为\(O(1)\),排序的时间为\(O(n\log n)\),最后统计加输出的时间为\(O(n)\),
整体时间复杂度为\(T(n)=n(O(m)+O(1))+O(n\log n)+O(n)=O(n\log n)\)
给出伪代码:
Procedure Begin telNumberArray <- empty For currentLine <- each line of input Begin telNumber <- parse tel number from currentLine push telNumber at the end of telNumberArray End For Quick sort telNumberArray duplicates <- 0 noDuplicates <- true For i from 1 to n Begin If telNumberArray(i – 1) = telNumberArray(i) duplictates <- duplicates + 1 Else If duplicates > 0 Begin Print telNumberArray(i – 1) and duplicates duplicates <- 0 noDuplicates <- false End If If duplicates > 0 Begin Print telNumberArray(i – 1) and duplicates duplicates <- 0 noDuplicates <- false End If End For If noDuplicates Print “No duplicates.” End Procedure
哈希表
这是我最先想到的方法,不过在这里用起来感觉还不如其他两种方法爽。
总的来说就是把上一种方法中的数组换成哈希表,用于查找已经存在的电话号码。
哈希函数可以用电话号码右移若干位得到。(位移速度远快于取模运算)
时间复杂度与上一个方法在同一阶上,不过实际上应该会快不少。
平衡二叉查找树
在用哈希表解这道题的时候,我注意到一句话:"Arrange the output lines by telephone number in ascending lexicographical order."
而二叉查找树遍历时恰好会产生一个有序的输出。
而且二叉查找树的查找性能虽然低于哈希表,但是仍有不俗的表现,因此我觉得用AVL来解这道题是比较好的。
平均插入时间为\(O(n\log n)\),平均查找时间也为\(O(n\log n)\),
总的时间复杂度\(T(n) = n(O(m) + O(n\log n) + O(n\log n)) + O(n)\)。
总结
从算法分析的结果来看,第一种方法反而是时空复杂度和实现难度比较优秀的一种解法,事实又一次证明维护有序比一次排序消耗要大得多。
汗,因此用第一种方法实现1002而超时的同学们应该好好检查一下自己的代码~
另外,还有一些同学和我一样,没有注意到"If there are no duplicates in the input print the line:No duplicates."而WA了,在此提醒大家注意审题T_T
额外补充
昨天晚上跟同学聊天,同学提到这道题如果用Trie树一定非常快。汗了,确实没有想到,不过用Trie树绝对是最快的了。对于这道题来说,Trie树插入时间和查找时间都是\(O(1)\),然后遍历的时候就会得到一个有序的输出,总时间复杂度\(T(n) = n(O(1)) + O(n) = O(n)\)。
对不了解Trie树的同学有一幅图可以说明问题: