【题目描述】
大写字母(除了Q、Z)映射到2~9,具有相同标准格式(###-####)的为相同号码。以标准格式,按字典升序输出重复的号码。
【思路分析】
1. 存储结构
为了加快查找速度,采用无冲突的哈希表存这些7位数,故需要 long hashTable[10000000] 来存储每个号码的出现次数。
由于号码的个数不超过100000个,用 long keys[200000] 来存储重复号码,keyn代表该数组中存放了多少条号码,最后需要在keys上进行快速排序。
以上两个数组,要写成全局变量,否则在主函数中会堆栈溢出。
2. 号码转换为数字(哈希键)
由于号码的首位对应数字的最高位,而数字确定是为7位数,故可以从数字的最高位开始存入,跳过连字符‘-’,最终得到7位数字作为哈希键。转换函数 Change2Number() 代码如下所示:
long Change2Number(string &strline) { long result = 0; int bit = 6; for (int i(0); i < strline.length(); i++) { char c = strline[i]; if (c >= '0' && c <= '9') { result += pow(10.0, bit--) * (c - '0'); } else if (c >= 'A' && c <= 'P') { result += pow(10.0, bit--) * ((c-'A')/3 + 2); } else if (c >= 'R' && c <= 'Y') { result += pow(10.0, bit--) * ((c-'A'-1)/3 + 2); } else if (c == 'Q' || c == 'Z') { continue; } } return result; }
3. 对号码记数
获得转换的7位数index后,对相应的hashTable[index]值加1(hashTable[…]初始为0)。若hashTable[index]的值已经为1,说明这是第二次遇到该号码,则将其加入keys数组中。
重复此过程直到号码读完,对keys数组进行快速排序(为了练习一下快排我的代码是自己写的),可以调用现有的程序qsort(数组, 大小, 单元大小, 比较函数),如下代码所示:
qsort(keys, keyn, sizeof(long), cmp); int cmp(const void*a,const void*b)//快排自定义cmp { return *(int*)a-*(int*)b; }
4. 输出格式控制
如果keys中没有元素,则输出“No duplicates.”(后面的’.’不要漏了,这里我也WA了 = =!!)。
否则,一个个输出,由于键是长整型,如果直接输出,数字最前面若是0则无法输出,所以在输出时候要控制下格式,写成”%07d”。
char temp[10]; sprintf(temp, "%07d", keys[i]); //写成"%07d"前面才会补零 string resultline = temp; resultline.insert(3, "-"); cout<<resultline<<" "<<hashTable[ keys[i] ]<<endl;
【小结】
这道题的知识点主要在于:无冲突的哈希表构建(写成全局变量),快速排序与格式输出控制。
唉,认真读题目很重要的!“No duplicates.”后面的.和输出格式都卡了我好久,差点就要放弃了,不过还是坚持下来,这周在这两题上花了好多时间。
【附:完整代码】
#include <iostream>#include <string> #include <cmath>using namespace std; long Change2Number(string &strline) { bool flag = true; long result = 0; int bit = 6; for (int i(0); i < strline.length(); i++) { char c = strline[i]; if (c >= '0' && c <= '9') { result += pow(10.0, bit--) * (c - '0'); } else if (c >= 'A' && c <= 'P') { result += pow(10.0, bit--) * ((c-'A')/3 + 2); } else if (c >= 'R' && c <= 'Y') { result += pow(10.0, bit--) * ((c-'A'-1)/3 + 2); } else if (c == 'Q' || c == 'Z') { continue; } } return result; } long Partition(long arraylist[], long low, long high) { long toBePosition = arraylist[low]; while (low < high) { while (low < high && arraylist[high] >= toBePosition) high--; arraylist[low] = arraylist[high]; while (low < high && arraylist[low] <= toBePosition) low++; arraylist[high] = arraylist[low]; } arraylist[low] = toBePosition; return low; } void QSort(long arraylist[], long low, long high) { if (low < high) { long pos = Partition(arraylist, low, high); QSort(arraylist, low, pos-1); QSort(arraylist, pos+1, high); } } long keys[200000]; long hashTable[10000000]; long keyn = 0; int main() { int n; while (cin>>n) { keyn = 0; memset(hashTable, 0, sizeof(hashTable)); for (int i(0); i < n; i++) { string strline; cin>>strline; long index = Change2Number(strline); if (index >= 0) // there is no 'Q' or 'Z' in strline, add in hashTable { if (hashTable[index] == 1) { keys[keyn] = index; keyn++; } hashTable[index]++; } } if (keyn == 0) { cout<<"No duplicates."<<endl; //!! } else { QSort(keys, 0, keyn-1); for (int i(0); i < keyn; i++) { char temp[10]; sprintf(temp, "%07d", keys[i]); //!! string resultline = temp; resultline.insert(3, "-"); cout<<resultline<<" "<<hashTable[ keys[i] ]<<endl; } } } return 0; }