问题:
给定一个长度为 N 的数组 A = [A1, A2, · · · AN ],数组中有可能有重复出现 的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改 A2,A3,··· ,AN。
当修改 Ai 时,小明会检查 Ai 是否在 A1 ∼ Ai−1 中出现过。如果出现过,则 小明会给 Ai 加上 1 ;如果新的 Ai 仍在之前出现过,小明会持续给 Ai 加 1 ,直 到 Ai 没有在 A1 ∼ Ai−1 中出现过。
当 AN 也经过上述修改之后,显然 A 数组中就没有重复的整数了。 现在给定初始的 A 数组,请你计算出最终的 A 数组
输入
第一行包含一个整数 N。 第二行包含N个整数A1,A2,··· ,AN
输出
输出N个整数,依次是最终的A1,A2,··· ,AN。
样例输入
5
2 1 1 3 4
样例输出
2 1 3 4 5
分析:
1,可以采用暴力破解法,双层for循环,第一层,循环n个数,第二次循环i之前的数,碰到相同的,加1,j从0开始,继续判断是否有相同的
int n;
cin>>n;
int p[n];
for(int i=0;i<n;i++){
cin>>p[i];
for(int j=0;j<i;j++){
if(p[i]==p[j]){
p[i]++;
j=-1;
}
if(j==i-1){
break;
}
}
cout<<p[i]<<" ";
}
2,采用散列表法,用一个v数组用来存储每次访问过的数,记为1,没有访问的记为0,这个数组的下标就是你输入的数,对应的,这样可以找到对应的数是否被访问过
比如:
int v[1000099];
for(int i=0;i<1000099;i++){
v[i]=0;
}
int n;
cin>>n;
int *p=new int[n];
for(int i=0;i<n;i++){
cin>>p[i];
while(1){
if(v[p[i]]==1){//说明被访问过
p[i]++;
}else{//没有被访问过的,就赋予1
v[p[i]]=1;
break;
}
}
cout<<p[i]<<" ";
}
3,优化上面的散列表法,我们发现,如果把v数组改为存储每个数访问的次数的时候,循环的次数又会变少
如果v[i]=k,说明i这个元素被访问过k次了,后面的k个元素也都被访问过了,只要访问i+k,看v[i+k]是否被访问过,一直到v[i]==0
int v[1000099];//存储每次访问的次数
for(int i=0;i<1000099;i++){
v[i]=0;
}
int n;
cin>>n;
int *p=new int[n];
for(int i=0;i<n;i++){
cin>>p[i];
while(1){
if(v[p[i]]!=0){//说明被访问过了,p[i]=他自身加上他访问过的次数
v[p[i]]++;
p[i]+=v[p[i]]-1;
}else{//没有被访问过的,就自加1
v[p[i]]++;
break;
}
}
}
for(int i=0;i<n;i++){
cout<<p[i]<<" ";
}
结果: