python系列中最大的产品

时间:2016-02-19 09:39:19

标签: python python-2.7

1000位数字中具有最大产品的四个相邻数字是:

9 × 9 × 8 × 9 = 5832

73167176531330624919225119674426574742355349194934
96983520312774506326239578318016984801869478851843
85861560789112949495459501737958331952853208805511
12540698747158523863050715693290963295227443043557
66896648950445244523161731856403098711121722383113
62229893423380308135336276614282806444486645238749
30358907296290491560440772390713810515859307960866
70172427121883998797908792274921901699720888093776
65727333001053367881220235421809751254540594752243
52584907711670556013604839586446706324415722155397
53697817977846174064955149290862569321978468622482
83972241375657056057490261407972968652414535100474
82166370484403199890008895243450658541227588666881
16427171479924442928230863465674813919123162824586
17866458359124566529476545682848912883142607690042
24219022671055626321111109370544217506941658960408
07198403850962455444362981230987879927244284909188
84580156166097919133875499200524063689912560717606
05886116467109405077541002256983155200055935729725
71636269561882670428252483600823257530420752963450

查找具有最大产品的1000位数字中的13个相邻数字。这个产品有什么价值?

我对此问题的解决方案是:

def no(x):
    previous=0
    i=0
    t=1
    while i !=987:
        for num in x[i:i+13]:
            no=int(num)
            t=no*t

        if  t>previous:
            previous = t
        i=i+1
        t=1
    return previous  

还有其他好的有效方法来解决这个问题吗?因为我认为我的效率不高

6 个答案:

答案 0 :(得分:5)

您可以在max函数中使用生成器表达式,并使用适当的key函数来计算子数字的乘积。为此,您可以使用map函数将数字转换为整数和reduce(在python 3.X functools.reduce中)以计算整数的乘积。

>>> max((digits[i:i+13] for i in xrange(0, len(digits) - 12)), key=lambda x: reduce(mul, map(int, x)))
'5576689664895'

请注意,如果您的数字之间有新的换行符,则需要使用str.replace()方法删除它们。

digits = digits.replace('\n', '')

更优化的方法:

由于每次使用容器时都要处理13位数,以便在每次迭代中保留您的数字,这里最好的选择是deque()形式collections模块{{1它的弹出和推送操作的顺序是O(1)。然后你可以计算出前13位数的乘积,并且在每次推送和弹出时你的初始产品应该被弹出的项目和多个按推项目除。并且在每次迭代中,您只需使用最大乘积保留序列。

maxlen=13

演示:

from operator import mul
from collections import deque
from copy import copy

def cal_max_prod(container, current_product):
    max_container = {'seq': copy(container), 'prod': current_product}
    for i in digits[13:]:
        popped_item = int(container.popleft())
        container.append(i)
        try:
            push_item = int(i)
            current_product = (current_product / popped_item) * push_item
        except ZeroDivisionError:
            if '0' not in container:
                current_product = reduce(mul, map(int, container))
        else:
            if current_product > max_container['prod']:
                max_container['prod'] = current_product
                max_container['seq'] = copy(container)

    return ''.join(max_container['seq'])

答案 1 :(得分:1)

如果你想提高效率,你会注意到在数字n到n + 12和n + 1到n + 13之间的乘积,你有12个共同因素。

所以让我们注意d i [0,999]中i的n位数,p i 以d i开头的m个连续数字的乘积(你的要求中m = 13):

  • p i 是针对[0,1000-m]
  • 中的i定义的
  • p i + 1 = p i / d i * d i + m 当d != 0

在每次迭代中,当d i != 0时,你只做一个产品和一个师而不是12个产品,对于一个随机系列,这应该是10次中的9次

一如既往地优化算法,然后再考虑低级代码优化。但是......代码会更大或更复杂......

答案 2 :(得分:1)

为简单起见,请考虑3位数而不是13位数。前三位数字是:

731

他们的产品是21.接下来的三位数字是:

316

产品是18.我们想要一个有效的算法,所以我们必须回答的一个问题是:我们能否在731的产品中以恒定时间计算316的乘积?

答案是肯定的:如果我们查看数字,从731转到316,我们已删除了7并添加了6.但如果我们查看该产品,我们就会除以7并将乘以除以6.而不是计算7×3×1,然后计算3×1×6,然后计算1×6×7,依此类推(执行 n 每次乘法)我​​们可以计算上一个产品的下一个产品(仅执行1次乘法和1次除法)。

这是一个在线性时间内运行的高效算法草图:

def maxproduct(number, digits):
    """Calculate the maximum product of the n-adjacent digits of number."""
    zeros = 0
    product = 1
    result = 0

    # Calculate the first, initial product.
    for x in number[:digits]:
        x = int(x)
        if x:
            product *= int(x)
        else:
            # This digit is 0. This will make our product zero
            # too (losing information about other digits) and will
            # also cause trouble with division later. Instead of
            # storing the zero in the product, we increment a counter.
            zeros += 1

    if not zeros:
        # This product is the highest we have seen so far.
        result = product

    # Calculate the other products with the remaining digits.
    for i in range(digits, len(number)):
        # Digit to remove.
        x = int(number[i - digits])
        # Digit to add.
        y = int(number[i])

        if x:
            product //= x
        else:
            # The digit to remove is 0.
            zeros -= 1

        if y:
            product *= y
        else:
            zeros += 1

        if not zeros and product > result:
            result = product

    return result

答案 3 :(得分:0)

使用numpy,如果内存不是问题。从他的数字基准速度来看,速度似乎比OP代码快约10倍:

import numpy as np
def no2(x,d=13):
    k = len(x)-d
    t = np.ones(k,dtype=int)
    xa = np.fromiter(map(int,tuple(x)),dtype=int)
    for i in range(d): #xrange on python2.x
        t *= xa[i:k+i]
    return np.max(t)

要获取返回最大值的数字,请将np.max(t)替换为x[np.argmax(t):np.argmax(t)+d]。 例如:

no2('123456789101234123412351235324234324234')
1244160

基准

对您提供的字符串进行基准测试时,我发现:

#OP approach:
%timeit -n 100  no(x)
100 loops, best of 3: 3.49 ms per loop

#Kasramvd approach:
%timeit -n 100  no3=max((s[i:i+13] for i in range(0, len(s) - 12)), key=lambda x: reduce(mul, map(int, x)))
100 loops, best of 3: 4.22 ms per loop

#Andrea approach:
%timeit -n 100 no4(x,13) 
100 loops, best of 3: 777 µs per loop

#numpy approach:
%timeit -n 100  no2(x)
100 loops, best of 3: 315 µs per loop

当内存和速度都出现问题时:

使用字符串10 ^ 4倍(即10 ^ 7位)进行基准测试时:

#numpy
%timeit -n 10 no2(x5)
10 loops, best of 3: 2.2 s per loop

#OP code
%timeit -n 1 no(x5)
1 loop, best of 3: 37 s per loop

#Andrea code
%timeit -n 1 no4(x5,13)
1 loop, best of 3: 8.01 s per loop

这也比OP代码提高了大约10倍。因此,除非数组不能适合RAM(但字符串可以),否则numpy表现更好。

答案 4 :(得分:0)

 # I found this solution in this video  (https://www.youtube.com/watch?v=oSZZn7krnX0&list=PLO1D3YWS7ep3Zrh8B4SrhIsyxneg23x29&index=10)
 l='''
                73167176531330624919225119674426574742355349194934
                96983520312774506326239578318016984801869478851843
                85861560789112949495459501737958331952853208805511
                12540698747158523863050715693290963295227443043557
                66896648950445244523161731856403098711121722383113
                62229893423380308135336276614282806444486645238749
                30358907296290491560440772390713810515859307960866
                70172427121883998797908792274921901699720888093776
                65727333001053367881220235421809751254540594752243
                52584907711670556013604839586446706324415722155397
                53697817977846174064955149290862569321978468622482
                83972241375657056057490261407972968652414535100474
                82166370484403199890008895243450658541227588666881
                16427171479924442928230863465674813919123162824586
                17866458359124566529476545682848912883142607690042
                24219022671055626321111109370544217506941658960408
                07198403850962455444362981230987879927244284909188
                84580156166097919133875499200524063689912560717606
                05886116467109405077541002256983155200055935729725
                71636269561882670428252483600823257530420752963450'''
    number = l.strip()
    number = number.replace('\n','')
    largest_mul = 0
    lenght = 13
    for i in range(len(number)):
       mul = 1
       for n in number[i:i+lenght]:
            mul *= int(n)
            if mul > largest_mul:
                largest_mul = mul
        
    print(largest_mul)
        # 23514624000

答案 5 :(得分:-1)

data=list("
73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450")

print(len(data))

lst=list()

while True:

        x=list(data[0:13])

        pro=1

        for i in x:

            pro*=int(i)

        lst.append(pro)


        data.pop(0)

        if len(data)==12:

            break

print(max(lst))

print(len(data))

print(lst[0])