C++ 11新标准实现POJ No.1002-487-3279
487-3279(重复的电话号码查询)(标签:优先队列,哈希表)
题目描述
电话号码的标准格式是七位十进制数,并在第三、第四位数字之间有一个连接符。电话拨号盘提供了从字母到数字的映射,映射关系如下:
A, B, 和C 映射到 2
D, E, 和F 映射到 3
G, H, 和I 映射到 4
J, K, 和L 映射到 5
M, N, 和O 映射到 6
P, R, 和S 映射到 7
T, U, 和V 映射到 8
W, X, 和Y 映射到 9
Q和Z没有映射到任何数字,连字符不需要拨号,可以任意添加和删除。 TUT-GLOP的标准格式是888-4567,310-GINO的标准格式是310-4466,3-10-10-10的标准格式是310-1010。
如果两个号码有相同的标准格式,那么他们就是等同的(相同的拨号)
你的公司正在为本地的公司编写一个电话号码薄。作为质量控制的一部分,你想要检查是否有两个和多个公司拥有相同的电话号码。
Input
Output
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
解题思路
首先,经过对题目的分析可知,解决此题目的一般思路可划分模块如下:
Step1.输入号码薄中号码的数量(Input第一行)
Step2.若已输入的数量还未达到满容量,就输入一个未标准化(标准化的号码是指7位数字的号码,e.g.123-4567)的字符串;否则,跳到Step6
Step3.对上述输入的字符串进行标准化的转换
Step4.将标准化后的电话号码存储起来,保存到数据结构bank中,以便在后续继续输入其它号码时判断是否有重复号码
Step5.回到Step2
Step6.将bank中的号码进行一遍扫描,且记录多次重复出现的号码和出现次数到另一个数据结构preout中
Step7.对preout进行排序,并输出相应出现次数
观察以上步骤可发现,在Step2~Step5中,会对全部电话号码遍历一遍;在Step6中,扫描重复记录时遍历第二遍;并且在Step7中,我们对preout进行排序时,又将其中的一部分重复号码遍历了第三遍。所以,考虑是否可以在一次遍历中,将之前的三次遍历所做的事情一次性做完?于是,得到改进后的整体逻辑思路如下:
Step1.输入号码薄中号码的数量(Input第一行)
Step2.若已输入的数量还未达到满容量,就输入一个未标准化(标准化的号码是指7位数字的号码,e.g.123-4567)的字符串;否则,跳到Step6
Step3.对上述输入的字符串进行标准化的转换
Step4.将标准化后的电话号码存储起来,保存到数据结构bank中,若bank中已有这个号码,则标记这个号码出现的次数为上次出现的次数加一(++count);同时,若号码的出现次数等于2时,将号码插入到preout有序数据结构的适当位置,表示这个号码有重复,即将在程序的最后(Step6)顺序输出(数据结构bank和preout将在后文具体分析)
Step5.回到Step2
Step6.输出重复号码和相应出现次数
接下来就以上的步骤进行分步阐述:
Step1:(略)
Step2:(略)
Step3:对字符串的标准化包括去除连字符“-”和将非标准化号码中的字母转换为相应的数字。
去除连字符可对输入的非标准号码进行一次遍历去除。
转换为标准化号码时,会使用过多的switch-case语句,如下代码所示:
switch (s[i]){
case('A') {s[i] = ''; break;}
case('B') {s[i] = ''; break;}
case('C') {s[i] = ''; break;}
......
}
为避免使用过长代码,在转换时,可使用hash map存储字母到数字的转换关系。在C++ STL中,哈希映射的头文件为<unordered_map>。定义unordered_map类对象search_dict。并对hash map在构造函数中初始化。如下代码所示:
Solution() {
/*初始化search_dict*/
search_dict[''] = '';
search_dict[''] = '';
search_dict['A'] = search_dict['B'] = search_dict['C'] = search_dict[''] = '';
search_dict['D'] = search_dict['E'] = search_dict['F'] = search_dict[''] = '';
search_dict['G'] = search_dict['H'] = search_dict['I'] = search_dict[''] = '';
search_dict['J'] = search_dict['K'] = search_dict['L'] = search_dict[''] = '';
search_dict['M'] = search_dict['N'] = search_dict['O'] = search_dict[''] = '';
search_dict['P'] = search_dict['R'] = search_dict['S'] = search_dict[''] = '';
search_dict['T'] = search_dict['U'] = search_dict['V'] = search_dict[''] = '';
search_dict['W'] = search_dict['X'] = search_dict['Y'] = search_dict[''] = '';
}
Step4:将转换后的标准化号码存储起来。因为每输入一个号码,要对此号码转换成标准号码后判断是否有重复,若在存储时选用简单的线性表结构,在查询重复操作时会产生O(n)的时间复杂度,因此,此处选用哈希表存储更高效。哈希表的key存储标准化后的号码,value存储号码出现的次数。在每次输入并转换成标准号码后,检查此号码是否在hash表中,若不在,则添加进去,并且value置为1。若已经存在,则value+1。
并同时进行判断,当value=2时,说明号码有重复,应当在程序末尾输出这个号码和对应的出现次数。所以应当新建一个数据结构进行重复号码的存储。value=2时,将号码追加进去。此处,又要做选择题了,应当用什么样的数据结构呢?这里可以选择可变长数组vector,对每个value=2的号码无序放入,等到程序末尾要输出时再排序;还有一个思路是用最小优先队列——即二叉堆来存储。二叉堆每次加入一个新元素或输出一个最小值的时间为log(N),但是连续加入或弹出N个元素的时间复杂度为N,而非Nlog(N)。所以理论上要比变长数组存储最后输出时排序稍快。并且如这篇博文所述,vector容量不够的话,会重新开辟一块更大容量的空间,并且将原数组中的内容拷贝到新的空间。这就导致,变长数组会浪费更多的程序运行时间。所以,此处选用优先队列存储将要输出的重复号码值。
Step5:(略)
Step6:在优先队列不为空时,连续将队列头的元素pop出来并且查询hash表中出现的次数,输出到标准输出即可。
(2019-11-22更新)在输出排序时,也可以选用二叉搜索树作为数据结构。这样,在顺序输出时,直接对二叉搜索树做中序遍历即可得到顺序排列的号码。选用二叉搜索树与优先队列的摊还时间复杂度是一样的。
if (dup_nums.size() == ) {
cout << "No duplicates." << endl;
}
else {
while (dup_nums.size() != ) {
string number = dup_nums.top();
dup_nums.pop();
int dup_count = count_dict[number];
number.insert(number.begin() + , '-');
cout << number << ' ' << dup_count << endl;;
}
}
源代码
C++ 11新标准实现POJ No.1002-487-3279的更多相关文章
- C++ 11新标准实现POJ No.1001-Exponentiation
Exponentiation(高精度幂计算)(标签:链表,字符串,快速幂计算) 题目描述 对数值很大.精度很高的数进行高精度计算是一类十分常见的问题.比如,对国债进行计算就是属于这类问题. 现在要你解 ...
- C++ 11新标准实现POJ No.2195-GoingHome
Going Home(回家)(标签:二部图,匈牙利算法,KM算法) 题目描述 在网格地图上,有n个男人和n个房屋. 在每个单位时间内,每个小人都可以水平或垂直移动一个单位步长到相邻的点. 对于每个小人 ...
- C++11新标准学习
<深入理解C++11:C++11新特性解析与应用> <华章科技:深入理解C++11:C++11新特性解析与应用>一共8章:第1章从设计思维和应用范畴两个维度对C++11新标准中 ...
- C++11新标准:nullptr关键字
一.nullptr的意义 1.NULL在C中的定义 #define NULL (void*)0 2.NULL在C++中的定义 #ifndef NULL #ifdef __cplusplus #defi ...
- C++11新标准:decltype关键字
一.decltype意义 有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了).为了满足这一需求,C++11新标准引入了decltype类型 ...
- C++11新标准:auto关键字
一.auto意义 编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然后要做到这一点并非那么容易.为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能 ...
- c++11新标准for循环和lambda表达式
:first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...
- 关注C++细节——C++11新标准之decltype的使用注意
c++11新特性--decltype decltype是C++11加入的一个新的keyword,目的是选择并返回操作数的数据类型,重要的是,在此过程中编译器分析表达式并得到它的类型,却不实际计算表达式 ...
- 基于c++11新标准开发一个支持多线程高并发的网络库
背景 新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间. 之前我也写过基于ACE的网络server框架,但A ...
随机推荐
- redis在mac上的下载安装
redis官网下载压缩包: 在终端进入下载后的目录,然后: 解压:tar zxvf redis-5.0.5.tar.gz 移动到:sudo mv redis-5.0.5 /usr/local 切换到: ...
- Linux入门(用户操作及权限)
Linux入门之 用户操作及权限 在一个公司里,老板与员工有上下级之分,员工与员工间也有上下级或同级之分.每个级别在公司的职责不同,权限也不同.在Linux操作系统中也一样,不同的用户身份拥有着不 ...
- spring5 源码深度解析----- 事务的回滚和提交(100%理解事务)
上一篇文章讲解了获取事务,并且通过获取的connection设置只读.隔离级别等,这篇文章讲解剩下的事务的回滚和提交 回滚处理 之前已经完成了目标方法运行前的事务准备工作,而这些准备工作最大的目的无非 ...
- kettle 利用 HTTP Client 获取猫眼电影API近期上映相关信息,并解析json
前言 Kettle 除了常规的数据处理之外,还可以模拟发送HTTP client/post ,REST client. 实验背景 这周二老师布置了一项实验: 建立一个转换,实现一个猫眼API热映电影的 ...
- 一篇干货满满的 NFS 文章
目录 NFS 1. 安装 2. 配置 3. 启动并添加到开机自启 4. NFS 客户端挂载 5 报错与解决办法 6. Win 系统安装 NFS client NFS 1. 安装 yum install ...
- [牛客网NOIP赛前集训营-普及组(第二场)]D-合法括号序列
链接:https://www.nowcoder.com/acm/contest/165/D来源:牛客网 合法括号序列 键盘上有左括号(,右括号),和退格键-,共三个键. 牛牛希望按键n次,使得输入的字 ...
- [CODEVS1537] 血色先锋队 - BFS
题目描述 Description 巫妖王的天灾军团终于卷土重来,血色十字军组织了一支先锋军前往诺森德大陆对抗天灾军团,以及一切沾有亡灵气息的生物.孤立于联盟和部落的血色先锋军很快就遭到了天灾军团的重重 ...
- Python开发【第四篇】语句与函数
语句 statement 语句是由一些表达式组成,通常一条语句可以独立的执行来完成一部分事情,并且形成结果. 多条语句写在一行内要用分号分开 例子: print('hello world') #这是一 ...
- 浅谈原理--hashCode方法
我们时常会判断一个元素是否相等重复,可以用equals方法. 每增加一个元素,我们就可以通过equals方法判断集合中的每一个元素是否重复,但是如果集合中有10000个元素了,我们每添加一个元素的时候 ...
- 【Go】高效截取字符串的一些思考
原文链接:https://blog.thinkeridea.com/201910/go/efficient_string_truncation.html 最近我在 Go Forum 中发现了 [SOL ...