我在面试时遇到一个问题,这很有挑战性。该主题基于决策分析。问题是让我们假设我们有一个元组;
(15, 8, 8, 3)
我们希望逐个创建所有组合的所有总和,而不重复和求和相同的数字,例如此输出;
[(23, 8, 3), (18, 8, 8), (15, 11, 8)]
另一个例子;
(6, 5, 3, 8)
输出是:
[(11, 3, 8), (9, 5, 8), (14, 5, 3), (6, 8, 8), (6, 13, 3), (6, 5, 11)]
注意:订单很灵活。
我真的很想知道答案,所以如果有人对这个编码挑战感兴趣,会帮助我改善思维结构。
答案 0 :(得分:5)
我认为解决此类问题的最佳方法是从缓慢,强力的解决方案开始,因为这样您就可以直观地看到工作的进展情况。其他人不同意并且更愿意预先考虑可能的算法,但这是我的答案,所以......
首先忽略重复的数字规则,使事情更简单:
def sumcombos(tup):
for i, x in enumerate(tup):
for j, y in enumerate(tup[i+1:], i+1):
yield tup[:i] + (x+y,) + tup[i+1:j] + tup[j+1:]
你应该能够理解它是如何工作的,对吧?
如果您明确需要list
tuple
而不是任何可迭代的,请将其换行:
def sumcomboslist(lst):
return list(sumcombos(lst))
现在,问题是这将输出(23, 8, 3)
两次,并且它还将输出(15, 16, 3)
。避免这种情况的规则是"不重复和总结相同的数字"。解释这意味着什么并不容易, * 但是一旦你这样做,实现它是:
def sumcombos(lst):
for i, x in enumerate(lst):
if x in lst[:i]: continue
for j, y in enumerate(lst[i+1:], i+1):
if y in lst[:j]: continue
yield tup[:i] + (x+y,) + tup[i+1:j] + tup[j+1:]
那么,表现是什么?好吧,内循环显然会运行N**2
次,并且我们有一个if y in lst[:j]
在该循环中占用线性时间,所以它是N**3
。现在,对于我们的例子,有史以来最大的N
是4,这很好,但在大多数现实情况下,立方算法都是个问题。
如果我们可以使用线性空间,我们可以通过构建一个前端将每个值映射到其第一个位置(仅需要线性时间)来改进它,然后if y in lst[:j]:
成为常量时间{ {1}}。
然后我们可以将这个memoization更进一步并缓存所有子列表的结果,因此内部循环只需要在第一次计算每个子目录。
但是,一旦你完成了这项工作,你就可以看到实际发生了什么(如果没有,在中间添加一些if first_positions[y] < j:
)并提出更聪明的算法来存储所有内容预先结对。
*规则很模糊,本页面上的每个人(包括我)都错误地认为它是什么意思。考虑到可以解释和查看预期输出的所有方式,我想我可以弄清楚它们必须具有什么意义。但在现实生活中,我绝对会要求他们澄清而不是猜测。对于一次采访来说更是如此,让你要求澄清可能实际上就是重点。
答案 1 :(得分:1)
set
答案 2 :(得分:0)
您可以尝试这种方法:
import itertools
final_=[]
for m in list(itertools.permutations(order,r=4)):
if m[:2][0]==m[:2][1]:
pass
else:
final_.append(tuple(sorted((sum(m[:2]),)+m[2:])))
print(set(final_))
输出:
when order=(15, 8, 8, 3)
输出:
{(3, 8, 23), (8, 8, 18), (8, 11, 15)}
order=(6, 5, 3, 8)
输出:
{(5, 8, 9), (3, 8, 11), (3, 5, 14), (6, 8, 8), (5, 6, 11), (3, 6, 13)}