487-3279(重复的电话号码查询)(标签:优先队列,哈希表)

题目描述

企业喜欢用容易被记住的电话号码。让电话号码容易被记住的一个办法是将它写成一个容易记住的单词或者短语。例如,你需要给滑铁卢大学打电话时,可以拨打TUT-GLOP。有时,只将电话号码中部分数字拼写成单词。当你晚上回到酒店,可以通过拨打310-GINO来向Gino's订一份pizza。让电话号码容易被记住的另一个办法是以一种好记的方式对号码的数字进行分组。通过拨打必胜客的“三个十”号码3-10-10-10,你可以从他们那里订pizza。
电话号码的标准格式是七位十进制数,并在第三、第四位数字之间有一个连接符。电话拨号盘提供了从字母到数字的映射,映射关系如下:

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

输入的格式是,第一行是一个正整数,指定电话号码薄中号码的数量(最多100000)。余下的每行是一个电话号码。每个电话号码由数字,大写字母(除了Q和Z)以及连接符组成。每个电话号码中只会刚好有7个数字或者字母。

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;;
}
}

源代码

~~~Code~~~

C++ 11新标准实现POJ No.1002-487-3279的更多相关文章

  1. C++ 11新标准实现POJ No.1001-Exponentiation

    Exponentiation(高精度幂计算)(标签:链表,字符串,快速幂计算) 题目描述 对数值很大.精度很高的数进行高精度计算是一类十分常见的问题.比如,对国债进行计算就是属于这类问题. 现在要你解 ...

  2. C++ 11新标准实现POJ No.2195-GoingHome

    Going Home(回家)(标签:二部图,匈牙利算法,KM算法) 题目描述 在网格地图上,有n个男人和n个房屋. 在每个单位时间内,每个小人都可以水平或垂直移动一个单位步长到相邻的点. 对于每个小人 ...

  3. C++11新标准学习

    <深入理解C++11:C++11新特性解析与应用> <华章科技:深入理解C++11:C++11新特性解析与应用>一共8章:第1章从设计思维和应用范畴两个维度对C++11新标准中 ...

  4. C++11新标准:nullptr关键字

    一.nullptr的意义 1.NULL在C中的定义 #define NULL (void*)0 2.NULL在C++中的定义 #ifndef NULL #ifdef __cplusplus #defi ...

  5. C++11新标准:decltype关键字

    一.decltype意义 有时我们希望从表达式的类型推断出要定义的变量类型,但是不想用该表达式的值初始化变量(如果要初始化就用auto了).为了满足这一需求,C++11新标准引入了decltype类型 ...

  6. C++11新标准:auto关键字

    一.auto意义 编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型,然后要做到这一点并非那么容易.为了解决这个问题,C++11新标准引入了auto类型说明符,用它就能 ...

  7. c++11新标准for循环和lambda表达式

    :first-child { margin-top: 0px; } .markdown-preview:not([data-use-github-style]) h1, .markdown-previ ...

  8. 关注C++细节——C++11新标准之decltype的使用注意

    c++11新特性--decltype decltype是C++11加入的一个新的keyword,目的是选择并返回操作数的数据类型,重要的是,在此过程中编译器分析表达式并得到它的类型,却不实际计算表达式 ...

  9. 基于c++11新标准开发一个支持多线程高并发的网络库

    背景 新的c++11标准出后,c++语法得到了非常多的扩展,比起以往不论什么时候都要灵活和高效,提高了程序编码的效率,为软件开发者节省了不少的时间. 之前我也写过基于ACE的网络server框架,但A ...

随机推荐

  1. [ASP.NET Core 3框架揭秘] 依赖注入:控制反转

    ASP.NET Core框架建立在一些核心的基础框架之上,这些基础框架包括依赖注入.文件系统.配置选项和诊断日志等.这些框架不仅仅是支撑ASP.NET Core框架的基础,我们在进行应用开发的时候同样 ...

  2. meta标签中设置以极速模式打开网页

    1.网页meta标签中X-UA-Compatible属性的使用的极速模式 <meta http-equiv="X-UA-Compatible" content="I ...

  3. .NET Core 3.0中IAsyncEnumerable<T>有什么大不了的?

    .NET Core 3.0和C# 8.0最激动人心的特性之一就是IAsyncEnumerable<T>(也就是async流).但它有什么特别之处呢?我们现在可以用它做哪些以前不可能做到的事 ...

  4. 在web端使用html5访问远程桌面

    背景: 2019年12月5日,微软宣布放弃浏览器Edge,转而推出一款新的浏览器,而这款新浏览器将会采用谷歌的Chromium 内核... 好了,反正已经无力吐槽,微软烂尾的项目也不是一个两个了,之前 ...

  5. [Luogu1379]八数码难题

    题目描述 在3×3的棋盘上,摆有八个棋子,每个棋子上标有1至8的某一数字.棋盘中留有一个空格,空格用0来表示.空格周围的棋子可以移到空格中.要求解的问题是:给出一种初始布局(初始状态)和目标布局(为了 ...

  6. Netty - 粘包和半包(上)

    在网络传输中,粘包和半包应该是最常出现的问题,作为 Java 中最常使用的 NIO 网络框架 Netty,它又是如何解决的呢?今天就让我们来看看. 定义 TCP 传输中,客户端发送数据,实际是把数据写 ...

  7. windows与office激活

    暴风官网:www.baofengjihuo.com

  8. Bootstrap应用核心

    Bootstrap是当前世界最受欢迎的响应式.移动设备优先的门户和应用前端框架.它不是单一的CSS或JavaScript框架,而是完整的HTML.CSS.JavaScript框架,你可以仅通过Boot ...

  9. LeetCode122——Best Time to Buy and Sell Stock II

    题目: Say you have an array for which the ith element is the price of a given stock on day i. Design a ...

  10. 微信小程序文件压缩上传

    试用场景:上传图片过大,需进行压缩处理. 涉及微信API API 说明 文档 chooseImage 选择图片 https://developers.weixin.qq.com/miniprogram ...