1.查找类问题
我们首先会想到,顺序查找,复杂度为O(n),但是如果让你查找m数十万次,复杂度变为O(mn)可能会突破时间限制。
比如说这个题
#include<bits/stdc++.h>
using namespace std;
int main(){
int mark[200001]={0}; //这样全赋值成0了?
int a,b;
while(1){
scanf("%d%d",&a,&b);
if(a+b==0) break;
for(int i=a;i<=b;i++)
mark[i]++;
}
while(1){
scanf("%d%d",&a,&b);
if(a+b==0) break;
for(int i=a;i<=b;i++)
cout<<mark[i]<<' ';
cout<<endl;
}
return 0;
}
这个题的复杂度就是O(m*n),while是查找次数m,for是遍历一遍个数n。结果在编译器里对了,但做题时会超出时间限制。但这就是最简单的做法了,大无语。
想要减小复杂度,就得把n降低到logn。
有一个方法是二分查找法,只要给他排好序(用sort排序,复杂度是O(nlogn)),查找的复杂度就是O(mlogn)。
但有一个方法是万能的。
2.万能的hash算法
自己写哈希函数很费劲,还要考虑冲突啥的。大部分hash问题都可以用map解决。
写哈希要注意的问题
(1)不需要指定map的大小,直接赋值就行
(2)如果定义了map<int,int> M,那么M[x]的初始值为0
2.1静态查找
静态查找的意思是给定了你map后,不会再添加或删除一个元素了。动态就是在查找的过程中可能会改变map。
举个栗子。
注意:
(1)判断map里有没有一个string用的是 .find(string).函数,一直找完最后一个用的是.end()函数
#include<bits/stdc++.h>
using namespace std;
struct node{
string num;
string name;
string sex;
int age;
};
int main(){
map<string,node> M;
int number1;
int number2;
scanf("%d",&number1);
for(int i=1;i<=number1;i++){
node p;
cin>>p.num>>p.name>>p.sex>>p.age;
//scanf("%s %s %s %d",&p.num,&p.name,&p.sex,&p.age);
//用scanf会吃回车,导致只能输入一行
M[p.num]=p;
}
string result[10000];
scanf("%d",&number2);
for(int i=0;i<number2;i++){
cin>>result[i];
}
for(int i=0;i<number2;i++){
if(M.find(result[i])!=M.end())
cout<<M[result[i]].num<<" "<<M[result[i]].name<<" "<<M[result[i]].sex<<" "<<M[result[i]].age<<endl;
else
cout<<"No Answer!"<<endl;
}
return 0;
}
2.2 动态查找
注意:
(1)定义了map<int,int>后,M[x]就相当于增加一条元素
#include<bits/stdc++.h>
using namespace std;
struct node{
string num;
string name;
string sex;
int age;
};
int main(){
map<int,int> M;
int n,q;
int x;
cin>>n;
for(int i=0;i<n;i++){
cin>>x;
M[x]++;
}
cin>>q;
for(int i=0;i<q;i++){
cin>>x;
if(M[x]==0){
cout<<"no"<<endl;
M[x]++;
}
else
cout<<M[x]<<endl;
}
return 0;
}
注意:
(1)map的映射关系很明确了,就是一本书对应几个喜欢的人。那么最后输出的时候,还需要知道第i个人喜欢的是哪本书,所以要用一个int数组记录一下每个人喜欢什么书。
#include<bits/stdc++.h>
using namespace std;
int main(){
int N,M;
map<int,int> mpt;
int record[1000];
int book;
cin>>N>>M;
for(int i=0;i<N;i++){ //N个读者
cin>>book;
record[i]=book;
mpt[book]++;
}
for(int i=0;i<N;i++){ //N个读者
if(mpt[record[i]]==1) //只有他自己
cout<<"BeiJu"<<endl;
else
cout<<mpt[record[i]]-1<<endl;
}
return 0;
}
如果用数组来解决也很方便。只需要两个数组。一个记录第i个人喜欢的书的编号。一个记录第i本书有多少人借阅。
#include<bits/stdc++.h>
using namespace std;
int main(){
int N,M;
cin>>N>>M;
int reader[N+1];
int book[M+1];
memset(book,0,sizeof(book));//书的借阅人数初始化为0
int booki;
for(int i=1;i<=N;i++){
scanf("%d",&booki);
reader[i]=booki; //记录每个读者喜欢书的编号
book[booki]++;
}
for(int i=1;i<=N;i++){
int bookIndex=reader[i];
if(book[bookIndex]>1)
cout<<book[bookIndex]-1<<endl;
else
cout<<"BeiJu"<<endl;
}
return 0;
}