python,修改数组【第十届】【省赛】【研究生组】

核心思路是并查集: 

#用例子来解释

构建一个数组 f = [0,1,2,...,1000001],因为题目范围是0~1000000

3

2 1 1走一次

构建获取输入的数组arr = list(map(int,input().split())),arr = [2,1,1,3,4]

step1: arr[0],即:2进来,比对f[arr[0]] == 2即看f[2] == 2,发现一样则说明第一次进,则说明该值不用改变,

            直接返回原值后arr[0] = 2,然后f[arr[0]] = find(arr[0] + 1),即f[2] = find(3),由于此时find(3)还没有,故式子其实是f[2] = 3,此时的索引从2变为3,这个3就是表示下一个数的索引位置。这表示下一次找2会直接索引到3

step2:arr[1],即:1进来,比对f[arr[1]] == 1即看f[1] == 1,发现一样则说明是初始的,是第一次进,则说明该值不用改变,

            直接返回原值后arr[1] = 1,然后f[arr[1]] = find(arr[1] + 1),即f[1] = find(2),再进入函数后发现f[2] == 2不成立,则说明已经该2索引被占用。且此时f[2] = 3

             f[2] = find(f[2])即f[2] = find(3)继续找,由于此时f[3] == 3还没有变化说明该索引可以使用,故式子其实是f[2] = 3,这个3就是表示下一个数的索引位置。得到了结果f[2] = 3  -> find[2] = 3 -> f[1] = find(2) -> f[1] = 3,最后索引从1变为了3,这表示下一次只要是找2,1都会直接索引到3

step3:arr[2],即:1再进来,比对f[arr[1]] == 1即看f[1] == 1,发现不一样则说明是多次进,则执行f[x] = find(f[x])即得f[1] = find(f[1])

          又由step2得到,f[1] = 3,即f[1] = find(3),再递归进入函数后发现f[3] == 3成立,则说明已经该3索引可以使用,即得f[1] = 3

             返回主函数有arr[2] = 3,更新下一个索引f[arr[2]] = find[arr[2] + 1]即:f[3] = find[4],由于此时f[4] == 4成立,可以表示下一个数的索引位置.

#初始一个并查集数组
f=[]
for i in range(0,1000002):
    f.append(i)
#f = [0,1,2,...,1000001]
#寻找插入点,以下例子用2 1 1 3 4来解释
def find(x):
    if f[x] == x:#如果这两个数相等,说明该数第一次出现,不用修改直接返回,例如2,1第一次进直接返回2,1
        return x
    else:#该数x出现过,且f[x]对应着下一个索引位置,例如1第二次进,则由下面'*'号行得,f[1] = find(2) = 3
        f[x] = find(f[x])
        return f[x] 
#输入值,并把值提取到arr中
n = int(input())
arr = list(map(int,input().split()))
#开始查找合更新
for i in range(0,n):
    arr[i] = find(arr[i])#查找arr[i]的插入点,例如2此时有arr[0] = 2
    f[arr[i]] = find(arr[i]+1)#**********

#输出结果
for j in range(0,n):
    print(arr[j],end=" ")
# 5
# 2 1 1 3 4

#对并查集不是很了解的可以参考,以下c++实现的代码https://blog.csdn.net/qq_17807067/article/details/127081554

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值