刚看完这道题,我的第一反应是用散列表。对每行输入求标准格式,用后4位做为hash值,前3位最为特征值,用链表的方式处理冲突。
但写到一半,感觉自己2了。考虑最坏情况,先读入1000个有相同hash值,不同特征值的号码,然后重复最后一个数。
此时散列的时间会用到100000*1000,目测TLE。需要用6位做为hash值,1位做为特征值才能做到10^6的时间复杂度,还可能MLE。
又注意到总共才100000个读入,O(N*lgN)的时间复杂度够用,突然觉得,何必这么麻烦。
于是我改写了一个快排算法,然后。。。。。。
不是我长得太丑就是POJ数据太丑!反正我一直TLE,随机化快排也不行!
当时我的内心是崩溃的。
上网搜了一下,瞬间感觉智商被碾压了。
认真学习了map的数据结构之后,发现,这货时间复杂度不也是O(N*lgN)吗!
一怒之下,手撸红黑树,现在想想,都是泪啊。
//PKU_1002
//快速排序会超时
//利用红黑树实现
#include <iostream>
using namespace std;
class RB_Tree_Node{
public:
char color;
RB_Tree_Node * left,* right,* parent;
int key;
int num;
};
class RB_Tree{
public:
RB_Tree_Node * root,* nil;
RB_Tree() {
nil = new RB_Tree_Node;
nil->left=nil->right=nil->parent=nil;
nil->color='N';
root=nil;
}
~RB_Tree(){
delete nil;
}
void left_rotate(RB_Tree_Node * p) {
RB_Tree_Node * y = p->right;
p->right = y->left;
if (y->left!=nil)
y->left->parent=p;
y->parent = p->parent;
if (p->parent==nil)
root = y;
else if (p==p->parent->left)
p->parent->left = y;
else
p->parent->right = y;
y->left = p;
p->parent = y;
}
void right_rotate(RB_Tree_Node * p) {
RB_Tree_Node * y = p->left;
p->left = y->right;
if (y->right!=nil)
y->right->parent=p;
y->parent = p->parent;
if (p->parent==nil)
root = y;
else if (p==p->parent->left)
p->parent->left = y;
else
p->parent->right = y;
y->right = p;
p->parent = y;
}
void insert(RB_Tree_Node * p) {
RB_Tree_Node * x,* y;
x = root;
y = nil;
while (x!=nil) {
y=x;
if (p->key<x->key)
x=x->left;
else
x=x->right;
}
p->parent = y;
if (y==nil)
root=p;
else if (p->key<y->key)
y->left=p;
else
y->right=p;
p->left=nil;
p->right=nil;
p->color='R';
while (p->parent->color=='R')
if (p->parent==p->parent->parent->left){
y=p->parent->parent->right;
if (y->color=='R'){
p->parent->color='B';
y->color='B';
p->parent->parent->color='R';
p=p->parent->parent;
}
else if (p==p->parent->right){
p=p->parent;
left_rotate(p);
}
else {
p->parent->color='B';
p->parent->parent->color='R';
right_rotate(p->parent->parent);
}
}
else{
y=p->parent->parent->left;
if (y->color=='R'){
p->parent->color='B';
y->color='B';
p->parent->parent->color='R';
p=p->parent->parent;
}
else if (p==p->parent->left){
p=p->parent;
right_rotate(p);
}
else {
p->parent->color='B';
p->parent->parent->color='R';
left_rotate(p->parent->parent);
}
}
root->color='B';
}
RB_Tree_Node * next(RB_Tree_Node * p){
if (p->right!=nil){
p=p->right;
while (p->left!=nil)
p=p->left;
}
else if (p==p->parent->left){
return p->parent;
}
else {
while (p==p->parent->right)
p=p->parent;
p=p->parent;
}
return p;
}
RB_Tree_Node * begin(){
RB_Tree_Node * p=root;
while (p->left!=nil)
p=p->left;
return p;
}
RB_Tree_Node * end(){
RB_Tree_Node * p=root;
while (p->right!=nil)
p=p->right;
return p;
}
RB_Tree_Node * find(int k,RB_Tree_Node * p){
if (p==nil) return p;
if (p->key==k) return p;
else if (p->key>k) return find(k,p->left);
else return find(k,p->right);
}
};
int main(){
char ch;
int i,n,hash;
RB_Tree T;
RB_Tree_Node * p;
cin>>n;
getchar();
for(i=0;i<n;i++) {
//计算每行读入的hash值
hash=0;
do{
ch=getchar();
if (ch>='0' && ch<='9')
hash=hash*10+ch-'0';
else if (ch>='A' && ch<='P')
hash=hash*10+(int(ch)-'A')/3+2;
else if (ch>='R' && ch<='Y')
hash=hash*10+(int(ch)-'B')/3+2;
}
while (ch!='\n');
p=T.find(hash,T.root);
if (p->color=='N'){
p = new RB_Tree_Node;
p->key=hash;
p->num=0;
T.insert(p);
}
p->num++;
}
bool flag=true;
p=T.begin();
while (p->color!='N'){
if (p->num>1) {
hash=p->key;
flag=false;
if (hash<100000)
cout<<"00";
else if (hash<1000000)
cout<<"0";
cout<<hash/10000<<"-";
hash%=10000;
if (hash<10)
cout<<"000";
else if (hash<100)
cout<<"00";
else if (hash<1000)
cout<<"0";
cout<<hash<<' '<<p->num<<endl;
}
p=T.next(p);
}
if (flag)
cout<<"No duplicates."<<endl;
return 0;
}
等冷静下来,才真的想要剁手,电话号码由‘0’-‘9’这10个字符组成,长度固定为7位,总共100000个数据,7*100000<10^6,简直是摆好姿势让你基数排序啊!
然后我又看了看这200+行的代码,果断的——
下一题!