字节笔试10-8 合并

题目描述:
小红拿到一个数组,他可以进行合并的操作:两个相同的数x,合并之后从数组中删除,并添加一个2x。仅允许一次,可以添加任意一个值。
问最多能合并几次?

输入为,第一行:数组长度n,第二行:n个元素
输出为,你添加了什么数字,最多合并几次 (有多个答案的情况任意一种即可)

样例:
input
3
1 1 3

output
3 2

这个题目有一点难度,因为他的n最多是有10^5的,最多允许nlogn时间复杂度。我和朋友讨论后认为可以这么做:

①预处理:首先将数组中已有的相同元素合并,得到一个不重复的数组,合并次数为res1 ②统计最长的等比数列有多长,长为res2 ③答案等于res1+res2,至于添加了什么数字,就是等比数列的最小值。

解释一下为什么这么想:因为能合并肯定先合并,后面再考虑能不能加数字,能加的话什么才是最优解?那当然是能够造成多米诺骨牌效应的,也就是能够1合2,2合4这样一直推下去的,所以是一个等比数列,数列有多长就合并多少次,如果没有这样的等比数列,那我随便找个数合并也能多出1次。

代码如下:

from collections import Counter
#合并
n = int(input().strip())
arr = list(map(int,input().strip().split()))

#预处理
res = 0
cnt = Counter(arr)
while 1: #当存在重复元素时,继续循环
    cnt_new = Counter()
    for key in cnt:
        # print(cnt_new,cnt,key)
        if cnt[key]%2==1:
                cnt_new[key] = 1
        if cnt[key]>=2:
            cnt_new[2*key] = cnt[key]//2
            res+=cnt_new[2*key]   
    #新老相等,跳出
    if cnt==cnt_new:break
    cnt = cnt_new
    
# print(cnt,res)

#算最长链长
keys = list(cnt.keys())
keys.sort()
vis = set()
max_chain_len = 1
head = keys[0]
for key in keys:
    tmp = 0
    cur = key
    while cur in cnt and cur not in vis:
        vis.add(cur)
        cur*=2
        tmp+=1
    if tmp>max_chain_len:
        max_chain_len = tmp
        head = key
res+=max_chain_len
print(head,res)

#字节跳动##笔试##牛客在线求职答疑中心#
全部评论
你好,你的问题我已经理解了。首先,这个题目的解题思路非常清晰,你通过预处理和计算最长链长,得到了合并次数的最优解。 关于添加了什么数字,你的解释也很合理,因为能够造成多米诺骨牌效应的等比数列是最优解,所以答案是等比数列的最小值。 你的代码也非常简洁,逻辑清晰,易于理解。 总的来说,你的解题思路和代码都非常优秀,为你点赞!
点赞 回复 分享
发布于 2023-10-09 15:56 AI生成

相关推荐

小谷围鸡肉卷阿姨:+1,腾子投完一动不动
点赞 评论 收藏
分享
shtdbb_:还不错,没有让你做了笔试再挂你
点赞 评论 收藏
分享
2 3 评论
分享
牛客网
牛客企业服务