原题链接
数据范围
1≤T≤100,
2≤n≤2×105,
0≤fi≤n,至少两个 fi 为 0。
同一测试点内所有 n 的和不超过 2×105。
数据保证有解。
输入样例:
3
5
5 0 0 2 4
7
7 0 0 1 4 0 6
7
7 4 0 3 0 5 1
输出样例:
5 3 1 2 4
7 3 2 1 4 5 6
7 4 2 3 6 5 1
将缺少的数倒放,这样最多会出现一个a[ i ] == i的情况,这时再去找另一个要填的数(原本为0的数)交换即可,因为a[ i ] == i,与i匹配的只有ai,所以随便找一个其他的数交换即可(必须原本为0)
因为a[i] == i 的情况不多,所有时间复杂度还是O(n)
AC代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 3;
int a[maxn], b[maxn];
void swap(int &x,int &y){x^=y^=x^=y;}
int flag[maxn];
int main(){
int T;
scanf("%d", &T);
while(T--){
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++ i)flag[i] = b[i] = 0;
for(int i = 1; i <= n; ++ i){
scanf("%d", &a[i]);
if(a[i])flag[a[i]] = 1, b[i] = 1;
}
int t = n;
for(int i = 1; i <= n; ++ i){
if(a[i] == 0){
while(flag[t] != 0)t--;
a[i] = t;
flag[t] = 1;
}
}
for(int i = 1; i <= n; ++ i){
if(a[i] == i){
int x = 1;
while(x <= n){
if(!b[x] && x != i){
swap(a[i], a[x]);
break;
}
x++;
}
flag[t] = 1;
}
}
for(int i = 1; i <= n; ++ i)
printf("%d ", a[i]);
printf("\n");
}
return 0;
}