1.题目
【问题描述】
给定一个长度为N的数组$A=[A_1,A_2,\dots,A_N]$,数组中有可能有重复出现的整数。
现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改$A_2,A_3,\dots,A_N$当修改$A_i$;时,小明会检查$A_i$是否在$A_1 \rightarrow A_{i-1}$中出现过。如果出现过,则小明会给$A_i$加上$1$;如果新的$A_i$仍在之前出现过,小明会持续给$A_i$加上1直到$A_i$没有在$A_1 \rightarrow A_{i-1}$中出现过。
当$A_n$也经过上述修改之后,显然A数组中就没有重复的整数了。
现在给定初始的A数组,请你计算出最终的A数组。
【输入格式】
第一行包含一个整数$N$。
第二行包含N个整数$A_1,A_2,\dots,A_N$
【输出格式】
输出N个整数,依次是最终的$A_1,A_2,\dots,A_N$
【样例输入】
5
2 1 1 3 4
【样例输出】
2 1 3 4 5
【评测用例规模与约定】
对于80%的评测用例,$1 \leq N \leq 10000$。
对于所有评测用例,$1 \leq N \leq 100000,1 \leq A_i \leq 1000000$。
2. 题解
2.1 思路分析
思路1:暴力求解(80分)
用一个set保存已遍历过的数字,当遍历到新的位置时,如果再set里则一直++,再将其加入回set
思路2:并查集
维护并查集并通过查操作直接找到A_i
2.2 代码实现
- 思路1:暴力求解
// 暴力求解 80分
import java.util.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
public static void main(String[] args) {
int N = scanner.nextInt();
int[] arr = new int[N];
for (int i = 0; i < N; i++) {
arr[i] = scanner.nextInt();
}
Set<Integer> set = new HashSet<>();
for (int i = 0; i < N; i++) {
while (set.contains(arr[i])){
arr[i]++;
}
set.add(arr[i]);
}
for (int i = 0; i < N-1; i++) {
System.out.print(arr[i]+" ");
}
System.out.println(arr[N-1]);
}
}
- 思路2:并查集
// 并查集 80分
import java.util.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int[] find = new int[1000001];
// 查操作 找到x的真正祖先
public static int findRoot(int x){
return x==find[x]?x:findRoot(find[x]);
}
public static void main(String[] args) {
int N = scanner.nextInt();
int[] arr = new int[N];
// 初始化find数组(用于查找祖先)
for (int i = 0; i < find.length; i++) {
find[i] = i;
}
for (int i = 0; i < N; i++) {
arr[i] = scanner.nextInt();
int root = findRoot(arr[i]); //找到目标A_{i-1}
arr[i] = root;
find[root] = findRoot(root+1);// 并操作 用并查集维护大小关系
}
for (int i = 0; i < N-1; i++) {
System.out.print(arr[i]+" ");
}
System.out.println(arr[N-1]);
}
}
// 并查集+路径压缩 100分
import java.util.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int[] find = new int[1000100];
// 查操作 找到x的真正祖先 增加路径压缩降低耗时
public static int findRoot(int x){
if(x==find[x]){
return x;
}else {
find[x] = findRoot(find[x]);
return find[x];
}
}
public static void main(String[] args) {
int N = scanner.nextInt();
int[] arr = new int[N];
// 初始化find数组(用于查找祖先)
for (int i = 0; i < find.length; i++) {
find[i] = i;
}
for (int i = 0; i < N; i++) {
arr[i] = scanner.nextInt();
int root = findRoot(arr[i]); //找到目标A_{i-1}
arr[i] = root;
find[root] = findRoot(root+1);// 并操作 用并查集维护大小关系
}
for (int i = 0; i < N-1; i++) {
System.out.print(arr[i]+" ");
}
System.out.println(arr[N-1]);
}
}
2.3 提交结果
- 思路1:暴力求解
评测点序号 | 评测结果 | 得分 | CPU使用 | 内存使用 | 下载评测数据 |
---|---|---|---|---|---|
1 | 正确 | 10.00 | 125ms | 22.51MB | 输入 输出 |
2 | 正确 | 10.00 | 93ms | 22.47MB | VIP特权 |
3 | 正确 | 10.00 | 93ms | 22.62MB | VIP特权 |
4 | 正确 | 10.00 | 125ms | 31.51MB | VIP特权 |
5 | 正确 | 10.00 | 656ms | 158.1MB | VIP特权 |
6 | 正确 | 10.00 | 484ms | 149.7MB | VIP特权 |
7 | 正确 | 10.00 | 765ms | 242.9MB | VIP特权 |
8 | 正确 | 10.00 | 531ms | 156.5MB | VIP特权 |
9 | 运行超时 | 0.00 | 运行超时 | 287.7MB | VIP特权 |
10 | 运行超时 | 0.00 | 运行超时 | 287.8MB | VIP特权 |
- 思路2:并查集
评测点序号 | 评测结果 | 得分 | CPU使用 | 内存使用 | 下载评测数据 |
---|---|---|---|---|---|
1 | 正确 | 10.00 | 125ms | 26.23MB | 输入 输出 |
2 | 正确 | 10.00 | 125ms | 26.23MB | VIP特权 |
3 | 正确 | 10.00 | 78ms | 26.39MB | VIP特权 |
4 | 正确 | 10.00 | 156ms | 30.05MB | VIP特权 |
5 | 正确 | 10.00 | 296ms | 40.35MB | VIP特权 |
6 | 正确 | 10.00 | 296ms | 42.53MB | VIP特权 |
7 | 正确 | 10.00 | 328ms | 40.65MB | VIP特权 |
8 | 正确 | 10.00 | 281ms | 40.58MB | VIP特权 |
9 | 正确 | 10.00 | 609ms | 96.44MB | VIP特权 |
10 | 正确 | 10.00 | 484ms | 97.01MB | VIP特权 |
评论 (0)