Python 已超出Itertools.COMPLORIES()提升时间限制

Python 已超出Itertools.COMPLORIES()提升时间限制,python,python-3.x,performance,Python,Python 3.x,Performance,我试图解决这个Python编码问题: 描述:安布罗西奥老师正在教他的学生二进制数 女儿安布罗西尼塔,所以他决定创造一个游戏 安布罗西奥将给安布罗西尼塔N个数字,后者可以选择K个数字 在最初的N中,每选一个数字,她就得一分 相当于使用二进制表示的1的数目 号码 帮助安布罗西尼塔了解她能获得多少积分 条目: 第一个输入行包含一个整数T,表示数字 测试用例的数量 每个测试用例从一行开始,该行包含整数N(总数) 和K(可选择的数字) 每个案例的最后一个输入行包含N个整数,表示 安布罗西尼塔可以选择的数字

我试图解决这个Python编码问题:

描述:安布罗西奥老师正在教他的学生二进制数 女儿安布罗西尼塔,所以他决定创造一个游戏

安布罗西奥将给安布罗西尼塔N个数字,后者可以选择K个数字 在最初的N中,每选一个数字,她就得一分 相当于使用二进制表示的1的数目 号码

帮助安布罗西尼塔了解她能获得多少积分

条目:

第一个输入行包含一个整数T,表示数字 测试用例的数量

每个测试用例从一行开始,该行包含整数N(总数) 和K(可选择的数字)

每个案例的最后一个输入行包含N个整数,表示 安布罗西尼塔可以选择的数字

输出:

对于每个测试用例,打印一行,其中包含Ambrosinita的多少个点 我能挣

一,≤ T≤ 十,

一,≤ N≤ 10^3

0≤ K≤ N

0≤ 数字≤10^5

执行时间限制为2秒。我得到一个TLE错误,但输出与预期的相同。因此,输入必须具有一定的长度

这是我的密码:

import itertools

test_cases = int(input())

def binary(num):
    return format(num,'b')

def filter_string_1s(string):
    aux = ''
    for i in string:
        if i == '1':
            aux += i
    return aux

for i in range(test_cases):
    k = input().split()
    k = int(k[1])
    values = input().split()
    values = [int(i) for i in values]
    values = [filter_string_1s(str(binary(i))) for i in values]
    bin_values = []
    for combination in itertools.combinations(values,k):
        aux = 0
        for bin_number in combination:
            for i in bin_number:
                if i == '1':
                    aux += 1
        bin_values.append(aux)
    print(max(bin_values))
问题:为了在执行期限内解决问题,我应该采取哪些步骤来优化它

TLE=超过时间限制

这是一个“top-k”问题,而不是需要“k”组合的问题。为了便于阅读,让我们选择N=990,K=7。你需要在990分的列表中选择前7名

通过生成C(990,7)=912459983564271542400个组合,然后确定每个组合中的7个数字中的每一个都有多少位
1
。这就是为什么你没有时间了:你有990个数字要考虑,但是你在输入中重复每一个数字的比特数倍。

别说了。你所需要的只是浏览一下这个列表,并保留前7位的计数。列表中的7个数字之间没有交互作用。事实上,你甚至不必报告数字,只需报告总分

从七个零开始。现在遍历所有990个数字。任何时候你发现一个大于列表中最小元素的位计数(保持排序以便于参考),然后用新的分数替换它(并重新排序)。在所有990个数字的末尾,
sum
列表


此外,计算比特数比你现在做的要容易得多。将
int
转换为二进制字符串,并使用
str.count(1)
查看其中有多少
1
位。

她可以通过选择具有最多1位的K个数字来获得最大点数。因此,您只需计算每个数字的点,然后取顶部的K

例如:

import random

def maxPoints(K,N=None,numbers=None):
    numbers = numbers or [random.randrange(0,100001) for _ in range(N)]
    points  = sorted(bin(n).count("1") for n in numbers)
    return sum(points[-K:])

mp = maxPoints(3,numbers=[1,2,3,4,5])
print(mp) # 5

mp = maxPoints(1000,1000) 
print(mp) # will return instantly

解决了!谢谢大家

代码:


请把问题编辑成你的问题。我无法通过链接查看它。欢迎使用堆栈溢出!请提供您试图解决的问题的简要说明,而不是指向外部站点的链接。您知道为什么需要2秒以上的时间吗?你认为循环
itertools.combinations(value,k)
可以进行多少次迭代?@KevinWang在使用itertools.combinations()之前,我曾尝试从列表中删除重复的元素,但没有成功(我仍然得到了TLE)。@flsantos0101但是会有多少次迭代?
值的大小可以有多大?首先,对于范围(k):
sum+=nums[-1]
delnums[-1]
是拼写
mysum=sum(nums[-k:])的缓慢方式(注意,变量名更改;
sum
是一个内置变量,因此,如果命名局部变量
sum
,则不能使用它)第二,如果允许导入,并且
nums
的总大小足够大,那么使用
import
ing
heapq
并使用
heapq.nlargest
(只返回
k
最大元素的
list
)替换
sort
和切片可能会有一点好处(n log k)
而不是排序
O(n log n)
work)。有见地的评论!上面的代码执行时间为0.0448s。按照建议编辑后,它略微降低到0.0479s。谢谢!注意:第4段中描述的算法基本上就是
heapq.nlargest
为您所做的(它不保持它的排序,它只是保持它是一个堆,排序是最后一步;保持堆不变比保持完全排序的状态稍微便宜一些)。
test_cases = int(input())

for i in range(test_cases):
    k = input().split()
    k = int(k[1])
    nums = input().split()
    nums = [format(int(i),'b').count('1') for i in nums]
    nums.sort()
    sum = 0
    for i in range(k):
        sum += nums[-1]
        del nums[-1]
    print(sum)