蓝桥杯基础练习VIP-完美的代价

蓝桥杯基础练习VIP-完美的代价

对大佬的代码分析扒出来更详细的思路
https://blog.csdn.net/hallohalloha/article/details/113332805

n = int(input())
pal = list(input())

count = 0 #count用来计交换的次数
flag = 0  #flag判断是否已经有一个单独的奇个数的字符了
i=0 #用于计数外层丢弃的字符(单侧,比如左侧,用来最后计算单个奇数字符移动到中间的次数)

while(len(pal)>1):
    for k in range(len(pal)-1,0,-1):  # 从后面往前一直到索引1,寻找和pal[0]相同的pal[k]
        if pal[k] == pal[0]:
            #print(k)
            count += len(pal) - k - 1  # 计数器加 len(pal)-k-1这里是直接考虑把逆序遇到的一个字符放到右侧最外面,找到移动次数和索引的规律是关键!注意是把计算和移动分开来想,而不是真正的去交换移动!
            #print(count)
            #最外层的已构成回文,不考虑了
            pal.pop(0)#注:pal(i)被pop掉后,索引整体前移1,所以k的位置需要-1
            i+=1#记录扔掉了几层
            pal.pop(k-1)#把找到的字符直接移到最外层,即直接pop掉,因为前移了所以这里的k-1就是刚才的k
            break#这里的break很重要,比如最后剩到 aa,此时k==1,但是是找到了相同的;不能进入下面代码段!!

        elif k == 1:  # 逆序到找不到相同的,该字符只能放到中间,这个字符肯定是出现奇数次了,这是前提!
            pal.pop(0)  #找不到的这个数丢弃,不能影响后续判断,把移动和计算分开
            # impossible的两种情况:这里需要手写找出规律!重要
            # ①偶数个字符,却存在一个字符出现奇数次
            # ②奇数个字符,但已经有一个字符只出现奇数次了,不能再出现下一个,用flag==1 标志已经有一个字符出现了奇数次
            if n % 2 == 0 or flag == 1:
                print('Impossible')
                exit()
            flag = 1
            count += int(n/2) - i #把出现奇数次的字符直接移到中间需要的步数;注意这里的n是原先长度,n/2 是原先一半长,需要减去扔掉的长度才是距离中间的长度,也即交换次数(这样也是一个贪心的思想,不考虑其他交换,一直把这个换到中间去,肯定是最少步骤)
print(count)

反思:

  • 外围的字符构成回文数就直接扔掉,没有必要考虑,简化问题规模
  • 贪心的体现就是目标就是一个,把当前字符一直移动到位置上,管其他的,这样肯定最小
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值