我想循环两个同样长的集合,并确定每个集合中的元素是否也在数组中。
这是我已经解决的Hackerrank问题。但是,我正在使用Hackerrank来进一步理解Python。我一直在学习列表理解,虽然我确实相信我试图将它用作被认为是糟糕的生产代码,但我仍然希望根据自己的知识探索语言语法的可能性。
这是设置它的代码:
n, m = map(int, input().split())
arr = list(map(int, input().split()))
A = set(map(int, input().split()))
B = set(map(int, input().split()))
任务是为A和arr中的每个元素输出一个值为+1的整数,并为B和arr中的每个元素输出-1。
示例输入:
3 2
1 5 3
3 1
5 7
示例输出:
1
这实现了所需的结果:
print(sum([1 for a in A if a in arr]) + sum([-1 for b in B if b in arr]))
然而,这更接近我想要实现的目标:
sum([1 if a in arr else -1 if b in arr for a, b in zip(A, B)])
编辑(实际上更接近):
print(sum(1 if a in arr -1 if b in arr for a, b in zip(A, B)))
正如你所看到的那样,两者都是单行的,所以它不是试图减少代码,而是要理解列表理解和pythonic代码的可能性。如果这不可能或甚至不好的做法我也很感兴趣。
这是Hackerrank链接: https://www.hackerrank.com/challenges/no-idea
答案 0 :(得分:3)
如何将数组转换为设置和交叉点
arr
编辑: 此解决方案不适用于{{1}}
中的重复值答案 1 :(得分:2)
首先,放弃列表理解;使用生成器表达式将值直接提供给sum()
:
sum(1 for a in A if a in arr)
如果A
是集,请使用set.intersection()
method提取常用值,然后获取结果的长度:
len(A.intersection(arr)))
这比尝试为每个值测试arr
要快。这个确实首先生成一个新的set()
对象,但是之前你创建了一个列表,所以差别不大。
此时更简单只是减去第二个长度:
len(A.intersection(arr)) - len(B.intersection(arr))
您可以通过循环arr
并在arr
中针对A
或B
测试每个值来完全避免创建集合。这也是更快,因为集合成员资格测试是O(1)常数时间:
sum(1 if v in A else -1 if v in B else 0 for v in arr)
如果值a in arr
不存在,则对A
集中的每个值测试arr
的方法都需要a
的完整列表扫描;这使得针对列表的成员资格测试成为O(N)线性时间问题,并且对A
和中的每个值都对B
中的每个值执行此操作,因此您结束用O((A + B)* N)== O(KN)时间。针对集合测试arr
中的每个值仅为O(N * 1)== O(N)时间。
此外,如果arr
中的值不是唯一的,您的方法实际上会导致错误的答案;你只计算一次的快乐或不快乐的数字,而问题要求每次出现时都要对它们进行计数。
答案 2 :(得分:1)
你的解决方案很棒但是这里有一个问题。您为两组数字使用set
数据结构,为数组使用list
数据结构。当在列表顶部应用in
运算符时,您正在进行O(n)搜索,而在集合中,相同的操作是O(logn)(在python平均情况下是O(1)!)。所以你的总时间复杂度是O(2 * m * n)= O(m * n)。您可以以相反的方式搜索,例如:
For each element in array, if element in A then +1, if element in B then -1.
这个的总复杂度是O(n * 2 * logm)= O(n * logm)
有关python时间复杂性的更多信息here
答案 3 :(得分:0)
这是我提交的答案,正如我首先想到的那样使用列表理解。这只是必要的,因为数组可能具有相同元素的倍数,因此计数需要反映这一点。
n, m = map(int, input().split())
arr = list(input().split())
A, B = set(input().split()), set(input().split())
print(sum([(e in A) - (e in B) for e in arr]))
答案 4 :(得分:0)
解决问题的最有效方法可能是将A
和B
的项目放入字典(作为键),值为1
或{{1取决于他们来自哪个集合。这将允许您浏览列表-1
并轻松获取要添加到总和的值:
arr
结果的计算与在生成器表达式(ab_dict = {a: 1 for a in A}
ab_dict.update((b, -1) for b in B)
result = sum(ab_dict.get(x, 0) for x in arr)
)中使用几个条件运算符具有相同的计算复杂度,但是应该通过某个常数因子更快,因为对于每个项目,只有一个dict查找而不是两套会员资格考试。