POJ1002 487-3279
题目来源:http://poj.org/problem?id=1002
题目大意:
(背景)企业喜欢容易被人记住的电话号码。使一个电话号码容易被记住的一种方法是让它“拼”(spell)出来是一个好记的单词或短语(与手机键盘上的字母联系起来)。比如,你可以拨打好记的TUT-GLOP打电话给滑铁卢大学。有时,也可以只让号码的一部分拼成一个单词。当你晚上回到宾馆,你可以拨打310-GINO从Gino's订一份披萨。另一种让号码好记的方式是将号码分成好记的组。比如,你可以打“3个10”电话3-10-10-10订必胜客的pizza。
电话号码的标准形式是一个7位的十进制数字,前三位与后四位之间用短横线隔开。(如888-1200)。电话键盘提供了从字母到数字的映射规则:
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.
如果两个号码的标准形式相同,那么我们认为这两个号码是相同的。
你的公司在为本地商人们编辑一个电话号码薄,作为质量控制的一部分,你希望检查号码薄中是否存在相同的号码。
输入:测试数据仅含一个样例。第一行为一个正整数,为号码个数(最大到100,000)。接下来的每行为号码薄中的一个号码。号码可能含有数字、字母(大写,不含A和Z)和短横线。数字和字母的个数为7.
输出:每行输出一个出现多次的电话号码的标准形式,空格后输出该号码出现了多少次。按号码的升序输出。若没有重复号码输出一行文字:“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
测试数据:http://acm.student.cs.uwaterloo.ca/~acm00/regionals/
Contest Data -> Real -> Testing data and solutions -> E
解题关键:
1.建立字母->数字之间的映射关系
2.按映射关系进行映射,将所有号码转换为标准形式
3.将所得的标准形式进行排序和统计,输出统计结果
最开始用Java的HashMap做,发现内存和时间都大得惊人。所以这是第一次,可能也是最后一次用Java刷题了吧。
1 ////////////////////////////////////////////////////////////// 2 // POJ1002 487-3279 3 // Memory: 19176K Time: 5422MS 4 // Language: Java Result: Accepted 5 ///////////////////////////////////////////////////////////// 6 7 import java.util.HashMap; 8 import java.util.Map; 9 import java.util.Map.Entry; 10 import java.util.Scanner; 11 import java.util.TreeMap; 12 13 public class Main { 14 private Map<Character, Integer> mapper = new HashMap<Character, Integer>(); 15 16 public void initial() { 17 mapper.put('A', 2); 18 mapper.put('B', 2); 19 mapper.put('C', 2); 20 mapper.put('D', 3); 21 mapper.put('E', 3); 22 mapper.put('F', 3); 23 mapper.put('G', 4); 24 mapper.put('H', 4); 25 mapper.put('I', 4); 26 mapper.put('J', 5); 27 mapper.put('K', 5); 28 mapper.put('L', 5); 29 mapper.put('M', 6); 30 mapper.put('N', 6); 31 mapper.put('O', 6); 32 mapper.put('P', 7); 33 mapper.put('R', 7); 34 mapper.put('S', 7); 35 mapper.put('T', 8); 36 mapper.put('U', 8); 37 mapper.put('V', 8); 38 mapper.put('W', 9); 39 mapper.put('X', 9); 40 mapper.put('Y', 9); 41 } 42 43 public Map<Character, Integer> getMapper() { 44 return mapper; 45 } 46 47 public static void main(String[] args){ 48 Main test = new Main(); 49 test.initial(); 50 51 Scanner scanner = new Scanner(System.in); 52 Map<String, Integer> hMap = new TreeMap<String, Integer>(); 53 int lines = Integer.parseInt(scanner.nextLine().trim()); 54 if (lines == 1) { 55 System.out.println("No duplicates."); 56 } 57 String[] tels = new String[lines]; 58 for (int i = 0; i < lines; i++) { 59 tels[i] = scanner.nextLine(); 60 } 61 for (String line : tels) { 62 StringBuffer sb = new StringBuffer(); 63 for (int i = 0; i < line.length(); ++i) { 64 char ch = line.charAt(i); 65 if (Character.isLetter(ch)) { 66 sb.append(test.getMapper().get(ch)); 67 } else if (Character.isDigit(ch)) { 68 sb.append(ch); 69 } 70 } 71 sb.insert(3, '-'); 72 String key = sb.toString(); 73 if (hMap.containsKey(key)) { 74 hMap.put(key, hMap.get(key) + 1); 75 } else { 76 hMap.put(key, 1); 77 } 78 } 79 int tag = 0; 80 for (Entry<String, Integer> entry : hMap.entrySet()) { 81 String key = entry.getKey(); 82 int value = entry.getValue(); 83 if (value > 1){ 84 System.out.println(key + " " + value); 85 tag++; 86 } 87 } 88 if (tag == 0) { 89 System.out.println("No duplicates."); 90 } 91 scanner.close(); 92 return; 93 } 94 }
然后,发现题目给出的映射关系中,每三个字母映射到一个数字,可以用取模运算。用C++重写了一次。
1 ////////////////////////////////////////////////////////////////////////// 2 // POJ1002 487-3279 3 // Memory: 3040K Time: 1094MS 4 // Language: C++ Result: Accepted 5 ////////////////////////////////////////////////////////////////////////// 6 7 #include <iostream> 8 #include <string> 9 #include <algorithm> 10 11 using namespace std; 12 13 void output(string str, int cnt) { 14 for (int i = 0; i < 3; ++i) { 15 cout << str[i]; 16 } 17 cout << '-'; 18 for (int i = 3; i < 7; ++i) { 19 cout << str[i]; 20 } 21 cout << " " << cnt; 22 cout << endl; 23 } 24 25 int main(void) { 26 int n; 27 cin >> n; 28 int no = n; 29 string * ans = new string[n]; 30 while(no--) { 31 string buff; 32 string stdForm; 33 cin >> buff; 34 //转换为标准形式 35 for (string::iterator it = buff.begin(); it != buff.end(); ++it) { 36 if (isdigit(*it)) { 37 stdForm += *it; 38 } else if ((*it) >= 'A' && (*it) < 'Q') { 39 stdForm += (char) (((*it) - 'A') / 3 + '2'); 40 } else if ((*it) > 'Q' && (*it) < 'Z') { 41 stdForm += (char) (((*it) - 'A' - 1) / 3 + '2'); 42 } 43 } 44 ans[no] = stdForm; 45 } 46 sort(ans, ans + n); 47 bool flag = false; 48 int cnt = 1; 49 //统计 50 for (int i = 0; i < n; ++i) { 51 if (i + 1 == n) { 52 if (cnt != 1) { 53 output(ans[i], cnt); 54 } 55 } else if (ans[i + 1] == ans[i]) { 56 ++cnt; 57 flag = true; 58 } else { 59 if (cnt != 1) { 60 output(ans[i], cnt); 61 cnt = 1; 62 } 63 } 64 } 65 if (flag == false) { 66 cout << "No duplicates." << endl; 67 } 68 system("pause"); 69 return 0; 70 }
发现还是很慢,看了Discuss里别人的代码,把标准形式的保存形式由string改为int,把所有的cin、cout改为scanf和printf,果然快了不少。
1 ////////////////////////////////////////////////////////////////////////// 2 // POJ1002 487-3279 3 // Memory: 596K Time: 329MS 4 // Language: C++ Result: Accepted 5 ////////////////////////////////////////////////////////////////////////// 6 7 #include <cstdio> 8 #include <algorithm> 9 10 using namespace std; 11 12 int main(void) { 13 int n; 14 scanf("%d", &n); 15 int no = n; 16 int * ans = new int[n]; 17 while(no--) { 18 char buff[50]; 19 char c; 20 int stdForm = 0; 21 int i = 0; 22 scanf("%s", buff); 23 //转换为标准形式 24 while ((c = buff[i++]) != '\0') { 25 if (c >= '0' && c <= '9') { 26 stdForm = stdForm * 10 + c - '0'; 27 } else if (c >= 'A' && c < 'Q') { 28 stdForm = stdForm * 10 + (c - 'A') / 3 + 2; 29 } else if (c > 'Q' && c < 'Z') { 30 stdForm = stdForm * 10 + (c - 'A' - 1) / 3 + 2; 31 } 32 } 33 ans[no] = stdForm; 34 } 35 sort(ans, ans + n); 36 bool flag = false; 37 int cnt = 1; 38 //统计&输出 39 for (int i = 0; i < n; ++i) { 40 if (i + 1 == n) { 41 if (cnt != 1) { 42 printf("%03d-%04d %d\n", ans[i] / 10000, ans[i] % 10000, cnt); 43 } 44 } else if (ans[i + 1] == ans[i]) { 45 ++cnt; 46 flag = true; 47 } else { 48 if (cnt != 1) { 49 printf("%03d-%04d %d\n", ans[i] / 10000, ans[i] % 10000, cnt); 50 cnt = 1; 51 } 52 } 53 } 54 if (flag == false) { 55 printf("No duplicates.\n"); 56 } 57 system("pause"); 58 return 0; 59 }
我大概也就能优化成这样了,有大牛的实现30ms内完成,只能膜拜。