Hello
大家好,我是 @愿此后再无WA,可以叫我小A,也可以叫我愿愿,一位阳光帅小伙,对算法领域比较感兴趣。如果我的文章对您有用,欢迎持续关注,我们一起进步!
这题这似乎在实际生活中也会用到,感觉挺重要的,学到就是赚到。要用并查集来做,一开始我也想不到竟然能用并查集,哎,还得多多练习才有经验呀。如果不了解并查集的朋友可以点击这里。查看并查集的初步模板。
看完上面的视频相信你对并查集有了初步的了解。回到这一题,我们最先想到的思路应该是,遍历这个数组如果这个数字在前面出现过就让他加一,加一还出现就还要继续加,不断加一加到前面没有出现为止,但如果这样一个一个遍历的话那必定就会超时,所以要看看怎么才能优化他。
诶,你说假设我们已经知道了这个数加到多少才停下的话,是不能就能省掉中间加+1的环节实现优化的目的?假设给出的数字是3,加到8才停下,那么我们知道的一点就是3到7之间的元素一定都已经出现过,也就是3到7之间是连续的。连续有什么用呢?(对这题而言)连续就能进行值传递。比如一根水管唯有完整没破洞的情况下才能将水完好的运输,我们这些数字也是一样的道理,可以通过并查集不断将前面空缺的位置告诉给相邻的一个,上传下,下传下下…直到将值完好的传递给接下来的元素,告诉他上面空缺的位置在哪,这样的话就不能一个个找了。
具体思路我们结合代码看下,我这里使用的是字典,字典的好处有多少数据才开多少空间,不会像列表一样先开够多少空间才能进行计算。
def find(x): # 并查集查找模板
if x != bc[x]:
bc[x] = find(bc[x]) # 路径压缩
return bc[x]
N = int(input())
nums = list(map(int,input().split()))
bc = {}
for i in nums:
# 如果这个元素已经使用过,那么就找到它根节点位置
# 也是跟着他最后面那个连续的数字,然后+1,就是空缺的位置了
if i in bc:
i = find(i) + 1
# 如果本来不在字典里也能够直接打印,就是他本身的值
print(i,end=" ")
bc[i] = i # 标记该点已使用
# 关系连通
if i+1 < N and i+1 in bc: # 如果前面那个点使用过就将它的位置告诉给中间这个点
bc[i] = bc[i+1]
if i-1 >= 0 and i-1 in bc: # 如果后一个点也使用过,就将这个点得到的位置告诉给后一个点
bc[i-1] = bc[i]
通过关系连通我们就能将一段连续数字的最后一个数字的位置告诉给前面跟他连续的所有数字。