Python 数字的有序对
对于给定的数Python 数字的有序对,python,algorithm,python-3.x,math,optimization,Python,Algorithm,Python 3.x,Math,Optimization,对于给定的数N求总的可能有序对(x,y),使x和y小于或等于N,且x的位数之和小于y的位数之和 例如,n=6:存在21个可能的有序对,它们是[(0,1)、(0,2)、(0,3)、(0,4)、(0,5)、(0,6)、(1,2)、(1,3)、(1,4)、(1,5)、(1,6)、(2,3)、(2,4)、(2,5)、(2,6)、(3,4)、(3,5)、(3,6)、(4,5)、(5,6)] 这里x总是小于y,x的位数之和也小于y的位数之和,并且x和y都等于或小于N。这是我的简单方法,但这非常缓慢,在N=1
N
求总的可能有序对(x,y),使x和y小于或等于N,且x的位数之和小于y的位数之和
例如,n=6:存在21个可能的有序对,它们是[(0,1)、(0,2)、(0,3)、(0,4)、(0,5)、(0,6)、(1,2)、(1,3)、(1,4)、(1,5)、(1,6)、(2,3)、(2,4)、(2,5)、(2,6)、(3,4)、(3,5)、(3,6)、(4,5)、(5,6)]
这里x总是小于y,x的位数之和也小于y的位数之和,并且x和y都等于或小于N。这是我的简单方法,但这非常缓慢,在N=10000之前效果很好,之后表现很差
from itertools import permutations
n=100
lis=list(range(n+1))
y=list(i for i in permutations(lis,2) if i[0]<i[1] and sum(list(map(int,
(list(str(i[0]))))))<sum(list(map(int,(list(str(i[1])))))))
print(len(y))
从itertools导入置换
n=100
lis=列表(范围(n+1))
y=列表(i表示置换中的i(lis,2),如果i[0]
这是家庭作业吗
闻起来像是家庭作业。一个问题是,您仍然在生成所有排列,然后删除x大于或等于y的条目。另一个问题是,您正在为每次迭代重新计算y的位数之和,以便以后存储和比较。可能有一个更优雅的解决方案,您可以如果您知道将来的所有x条目都将不符合条件,那么实际上就是脱离嵌套循环
from itertools import permutations
from time import time
def time_profile(f):
def time_func(*args, **kwargs):
start_time = time()
r = f(*args, **kwargs)
end_time = time()
print "{} Time: {}".format(f, end_time - start_time)
return r
return time_func
@time_profile
def calc1(n):
lis=list(range(n+1))
y=list(i for i in permutations(lis,2) if i[0]<i[1] and sum(list(map(int,
(list(str(i[0]))))))<sum(list(map(int,(list(str(i[1])))))))
return y
@time_profile
def calc2(n):
l = []
for y in xrange(n+1):
y_sum = sum(map(int, str(y)))
for x in xrange(y):
# May be possible to use x_digits to break
x_digits = map(int, str(x))
if sum(x_digits) >= y_sum: continue
l.append((x, y))
return l
if __name__ == '__main__':
N = 10000
if len(calc1(N)) != len(calc2(N)): print 'fail'
从itertools导入置换
从时间导入时间
def时间_配置文件(f):
定义时间函数(*args,**kwargs):
开始时间=时间()
r=f(*args,**kwargs)
结束时间=时间()
打印“{}时间:{}”。格式(f,结束时间-开始时间)
返回r
返回时间函数
@时间剖面图
def calc1(n):
lis=列表(范围(n+1))
y=列表(i表示排列中的i(lis,2),如果i[0]时间:233.378999949
<0xfff2c09c时的函数计算C2>时间:84.967000076
与问题无关的其他几点。对list的一些调用是多余的。map函数已经返回了一个list。在Python 3中,range返回一个生成器,在您迭代时返回一个值。它的内存效率更高,工作原理也一样。代码的工作原理
这几乎完全是对您的方法的算法改进。使用生成器或列表理解可能更快,但您必须对其进行分析以进行检查。该算法的工作原理如下:
预计算1-N的数字和
将数字1-N按其数字和进行分组。我们有一个类似这样的对象。因此,如果我们想要得到数字和大于2的数字,我们只需要计算第三行之后的数字
1:1,10
2:2,11,20
3:3,12,21,30
注意每行中的数字都是按顺序排列的。如果我们的数字是12,我们只需要查看12之后的数字。我们可以通过二进制搜索找到每行中的12
总体而言,这比您的算法提高了约20倍,内存消耗为O(N)
代码
你的脚本产生了错误的输出,同时就像我说的那样,这对巨大的N不起作用,但我感谢你的努力:)嗯……如果你想要速度,数据库表可能是最好的方法。另外,你能在准确性方面添加更多细节吗?xfrom itertools import permutations
for _ in range(int(input())):
n=1000
lis=range(n+1)
y=(i for i in permutations(lis,2) if i[0]<i[1] and sum(map(int,(str(i[0]))))<sum(map(int,(list(str(i[1]))))))
print (sum(1 for _ in y))
def find_total_possible(n):
x = [i for i in range(n + 1)]
y = [i + 1 for i in range(n + 1)
z = list(zip(x,y))
return z
from itertools import permutations
from time import time
def time_profile(f):
def time_func(*args, **kwargs):
start_time = time()
r = f(*args, **kwargs)
end_time = time()
print "{} Time: {}".format(f, end_time - start_time)
return r
return time_func
@time_profile
def calc1(n):
lis=list(range(n+1))
y=list(i for i in permutations(lis,2) if i[0]<i[1] and sum(list(map(int,
(list(str(i[0]))))))<sum(list(map(int,(list(str(i[1])))))))
return y
@time_profile
def calc2(n):
l = []
for y in xrange(n+1):
y_sum = sum(map(int, str(y)))
for x in xrange(y):
# May be possible to use x_digits to break
x_digits = map(int, str(x))
if sum(x_digits) >= y_sum: continue
l.append((x, y))
return l
if __name__ == '__main__':
N = 10000
if len(calc1(N)) != len(calc2(N)): print 'fail'
import time
import bisect
import itertools
N = 6
def sum_digits(n):
# stolen from here: https://stackoverflow.com/questions/14939953/sum-the-digits-of-a-number-python
# there may be a faster way of doing this based on the fact that you're doing this over 1 .. N
r = 0
while n:
r, n = r + n % 10, n // 10
return r
t = time.time()
# trick 1: precompute all of the digit sums. This cuts the time to ~0.3s on N = 1000
digit_sums = [sum_digits(i) for i in range(N+1)]
digit_sum_map = {}
# trick 2: group the numbers by the digit sum, so we can iterate over all the numbers with a given digit sum very quickly
for i, key in enumerate(digit_sums):
try:
digit_sum_map[key].append(i)
except KeyError:
digit_sum_map[key] = [i]
max_digit_sum = max(digit_sum_map.keys())
# trick 3: note that we insert elements into the digit_sum_map in order. thus we can binary search within the map to find
# where to start counting from.
result = []
for i in range(N):
for ds in range(digit_sums[i] + 1, max_digit_sum + 1):
result.extend(zip(itertools.repeat(i), digit_sum_map[ds][bisect.bisect_left(digit_sum_map[ds], i):]))
print('took {} s, answer is {} for N = {}'.format(time.time() - t, len(result), N))
# took 0.0 s, answer is 21 for N = 6
# took 0.11658287048339844 s, answer is 348658 for N = 1000
# took 8.137377977371216 s, answer is 33289081 for N = 10000
# for reference, your last method takes 2.45 s on N = 1000 on my machine