IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【蓝桥杯试题】修改数组(并查集路径压缩) -> 正文阅读

[数据结构与算法]【蓝桥杯试题】修改数组(并查集路径压缩)

问题描述

给定一个长度为 N 的数组 A = [A?, A?, · · · AN],数组中有可能有重复出现的整数。
  现在小明要按以下方法将其修改为没有重复整数的数组。小明会依次修改
  A?, A?, · · · , AN。
  当修改 Ai 时,小明会检查 Ai 是否在 A? ~ Ai?? 中出现过。如果出现过,则小明会给 Ai 加上 1 ;如果新的 Ai 仍在之前出现过,小明会持续给 Ai 加 1 ,直到 Ai 没有在
  A? ~ Ai?? 中出现过。
  当 AN 也经过上述修改之后,显然 A 数组中就没有重复的整数了。现在给定初始的 A 数组,请你计算出最终的 A 数组。
输入格式
  第一行包含一个整数 N。
  第二行包含 N 个整数 A?, A?, · · · , AN 。
输出格式
  输出 N 个整数,依次是最终的 A?, A?, · · · , AN。
样例输入
5
2 1 1 3 4
样例输出
2 1 3 4 5
评测用例规模与约定
  对于 80% 的评测用例,1 ≤ N ≤ 10000。
  对于所有评测用例,1 ≤ N ≤ 100000,1 ≤ Ai ≤ 1000000。

解题思路i

80分思路:

使用flag数组标记出现过的数字,每输入一个数字Ai,判断flag[Ai]是否为1,如果为1就一直++Ai,直到flag[Ai] == 0
在这里插入图片描述
同样的思路,JAVA居然能AC,JAVA题解
在这里插入图片描述
代码:

#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
#include<cmath>
#include<numeric>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i,s,t) for(int i = (s);i<(t);++i)
#define N  100010
#define M  1000010
int arr[N];
bool flag[M];
int main() {
	int n;
	cin >> n;
	rep(i, 0, n) {
		cin >> arr[i];
		while (flag[arr[i]]) {
			++arr[i];
		}
		flag[arr[i]] = 1;
	}
	rep(i, 0, n) {
		cout << arr[i] << " ";
	}
	return 0;
}

100分思路:

开始没想到用并查集,参考文章后有了思路。
用并查集记录每个已经出现的数字的修改值,下一次出现该数字时直接用find函数查找即可。
使已经出现的数字的根结点为该数字的修改值,即pre[arr[i]] = arr[i] + 1,如果arr[i] + 1也出现过,那么arr[i] + 1的根结点就等于arr[i] + 2,依此类推。
因为Ai 最大值为1000000,如果循环给pre数组进行赋初值的话会浪费太多时间,所以直接把所有结点的根节点初始化为0 int pre[N] = {0},如果pre[x] == 0的话就表示x即为根节点。
但是这样依然会超时,因为虽然使用了并查集记录重复数字的修改值,可find函数在进行查找时还是会一层一层查找父结点,这样就和++Ai的操作没什么区别了。
如果能让指向父结点的子节点直接指向根节点,不就能做到O(1)的时间复杂度了吗。于是想到了并查集的路径压缩优化
代码:

#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
#include<cmath>
#include<numeric>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i,s,t) for(int i = (s);i<(t);++i)
#define N  100010
#define M  1000010
int arr[N];
bool flag[M];
int pre[N];//所有根结点初始化为0
int find_s(int x) {
	while (pre[x] != 0) {
		if(pre[pre[x]] != 0)
			pre[x] = pre[pre[x]];//压缩路径
		x = pre[x];
	}
	return x;
}

int main() {
	int n;
	cin >> n;
	rep(i, 0, n) {
		cin >> arr[i];
		if (flag[arr[i]]) {
			arr[i] = find_s(arr[i]);
		}
		pre[arr[i]] = arr[i] + 1;//将arr[i]的下一个数arr[i]+1作为其根结点
		flag[arr[i]] = 1;
	}
	rep(i, 0, n) {
		cout << arr[i] << " ";
	}
	return 0;
}

在这里插入图片描述
只用了93ms,c++ yyds!

上面的代码使用的是基于循环的路径压缩,虽然能有效压缩集合树的层数,但是还没有实现我们想让所有子节点都指向根结点的效果,于是使用基于递归的路径压缩,递归查找根节点,并在逐层返回根节点的过程中,修改字节点,使每个子节点都指向根结点。

#include<iostream>
#include<vector>
#include<string>
#include<iomanip>
#include<cmath>
#include<numeric>
#include<algorithm>
using namespace std;
typedef long long ll;
#define rep(i,s,t) for(int i = (s);i<(t);++i)
#define N  100010
#define M  1000010
int arr[N];
bool flag[M];
int pre[N];//所有根结点初始化为0
int find_s(int x) {
	if (pre[x] == 0) {
		return x;//返回根结点
	}
	else {
		pre[x] = find_s(pre[x]);//所有子节点指向根节点
		return pre[x];
	}
}

int main() {
	int n;
	cin >> n;
	rep(i, 0, n) {
		cin >> arr[i];
		if (flag[arr[i]]) {
			arr[i] = find_s(arr[i]);
		}
		pre[arr[i]] = arr[i] + 1;//将arr[i]的下一个数arr[i]+1作为其根结点
		flag[arr[i]] = 1;
	}
	rep(i, 0, n) {
		cout << arr[i] << " ";
	}
	return 0;
}

在这里插入图片描述
运行时间更短了。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-07 22:56:50  更:2022-04-07 23:00:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 9:36:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码