1 题目描述
n 个整数两两相加可以得到 n(n - 1) / 2个和。我们的目标是:根据这些和找出原来的 n 个整数。按非降序排序返回这 n 个数,如果无解,输出 "Impossible"。
2 解题思路
首先看到这题难度,小小中等,这还不简简单单拿下。仔细一看,好像不太对劲,题目的字都认识,读完咋完全没思路。这时候没思路也不能干瞪眼啊,试试这个豆包新出的AI功能,只需要点击右侧的AI->需要一点思路提示。
sums.sort()
然后假设现在对n个数求解,可以先设这n个数为:,并假设他们是按非递减排列的;假设是它们两两求和,而且也是非递减排序。这样我们就可以看出一些对应关系:
因为,所以可以想到第二小的为:
现在知道了两个等式,却有三个未知数,要是我们想求解,那么必须知道的值,显然我们并不能确定它,那么不妨假设我们知道,并假设它是:,我们知道两两求和,最多有n-1个和是由和其他值加和得来,而如果排除带有的和,那么将是最小的。也就能推断出,y的值最大为n,我们可以得到
那么现在我们就来开开心心地求出吧
对它求解有:
再来看看求得这些后有什么好处,首先我们可以排除x列表中的一些已知元素,先假设这里就可以排除掉,排除之后我们可以想到x中最小的值一定为,因为下标比4小的a值的两两组合已经被排除掉了。这样我们可以求得a_4的具体的值。然后在x中再排除掉。重复这个过程就可以求出所有的a值了。要是不行,那就改变y的值,直到所有的y值都试过后还是不能求出,那就返回“Impossible”。下面是具体的代码:
def solution(n, sums):
# 对和列表进行排序
sums.sort()
# 初始化结果列表
result = []
flag_used = [False]*len(sums)
# 递归推导整数
def deduce_numbers(sums, result, flag_used):
# 如果已经找到 n 个整数,返回结果
if len(result) == n:
return result
# 找到最小的和
index = -1
for i, item in enumerate(flag_used):
if not item:
index = i
break
if index == -1:
return result
result.append(sums[index] - result[0])
#去掉已知最小和
for x in result[:-1]:
flag_charge = 1
for i, item in enumerate(flag_used):
if not item and x + result[-1] == sums[i]:
flag_used[i] = True; flag_charge = 0
break
if flag_charge:
return result
return deduce_numbers(sums, result, flag_used)
#对a_3的值进行假设
min_sum_0 = sums[0]; min_sum_1 = sums[1]; flag_used[:2] = [True, True]
for i in range(2, n):
min_sum_2 = sums[i]; flag_used[i] = True
if (min_sum_0 + min_sum_1 + min_sum_2) % 2 == 1:
continue
result.append(int((min_sum_0 + min_sum_1 - min_sum_2) / 2))
result.append(int((min_sum_0 - min_sum_1 + min_sum_2) / 2))
result.append(int((min_sum_1 + min_sum_2 - min_sum_0) / 2))
result = deduce_numbers(sums, result, flag_used)
if len(result) == n:
break
result.clear(); flag_used[2:] = [False] * (len(sums) - 2)
# 如果结果长度为 n,返回结果;否则返回 "Impossible"
return " ".join(map(str, result)) if len(result) == n else "Impossible"
if __name__ == "__main__":
# You can add more test cases here
print(solution(3, [1269, 1160, 1663]) == "383 777 886")
print(solution(3, [1, 1, 1]) == "Impossible")
print(solution(4, [2, 2, 2, 2, 2, 2]) == "1 1 1 1")
print(solution(5, [226, 223, 225, 224, 227, 229, 228, 226, 225, 227]) == "111 112 113 114 115")
print(solution(5, [-1, 0, -1, -2, 1, 0, -1, 1, 0, -1]) == "-1 -1 0 0 1")
print(solution(5, [79950, 79936, 79942, 79962, 79954, 79972, 79960, 79968, 79924, 79932]) == "39953 39971 39979 39983 39989")
3 时间和空间复杂度分析
3.1 时间复杂度分析
首先有排序,复杂度为,其中m = , 再对递归调用部分分析,min_sum_3的种类最大可能为,对于每一种递归的深度最大为,在每一层中需要排除已知的最小x,这个最大的可能为,所以总的时间复杂度为,简化为。排除已知的最小值这部分可用二分查找,如果这样的话,时间复杂度可以进一步降低,为。看上去依旧非常吓人,不过目前笔者还没有找到时间复杂度更低的算法,希望评论区的大佬可以贡献高招。
3.2 空间复杂度分析
首先递归调用共n层,每层保存两个长度为的数组,空间复杂度就为
4 总结
不得不说豆包AI助手真的太好用了。豆包是一款非常出色的AI助手,它不仅能够快速准确地回答各种编程问题,还能提供详细的解题思路和代码优化建议。豆包的智能程度和响应速度令人印象深刻,它极大地提高了我的编程效率和学习体验。无论是初学者还是有经验的开发者,都能从豆包的帮助中受益匪浅。感谢豆包的辛勤工作和卓越表现。这道题目就是豆包提供的思路,以后的编程体验会大大提升,同样的工作量能在更少的时间内完成了。掌握AI辅助编程绝对能提高自身的优势和竞争能力。