简体   繁体   中英

Finding maximum product of 13 adjacent digits in 10,000 digit number

Can't seem to figure out what's wrong with my code (Project Euler problem 8). I want to find the maximum product of 13 adjacent digits in the 10,000 digit number below, and I'm getting the wrong answer.

my_list = list('7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450')

for i in range(1000):
    my_list[i] = int(my_list[i])

previous_product = 1
for x in range(13):
  previous_product *= my_list[x]
current_product = previous_product*my_list[13]/my_list[0]

for i in range(1, 987):
  if current_product > previous_product:
    maximum_product = current_product
  previous_product = current_product
  if my_list[i]==0:
    current_product = 1
    for x in range(13):
      current_product *= my_list[i+x+1]
  else:
    current_product = previous_product*my_list[i+x+1]/my_list[i]

print(maximum_product)

Edit: Solved! maximum_product was defined wrongly... it takes on the value of the most recent "current product" that happens to be greater than the previous product, not necessarily the largest product.

Correct, albeit not-super-efficient code:

   my_list = list('7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450')

for i in range(1000):
    my_list[i] = int(my_list[i])

previous_product = 1
for x in range(13):
  previous_product *= my_list[x]
current_product = previous_product*my_list[13]/my_list[0]

large_products = []

for i in range(1, 987):
  if current_product > previous_product:
    large_products.append(current_product)
  previous_product = current_product
  if my_list[i]==0:
    current_product = 1
    for x in range(13):
      current_product *= my_list[i+x+1]
  else:
    current_product = previous_product*my_list[i+x+1]/my_list[i]

print(max(large_products))

I haven't checked why your approach doesn't work but you can easily solve this with:

import operator
from functools import reduce

my_int_list = [int(char) for char in my_list]

max(map(lambda *x: reduce(operator.mul, x), 
        my_int_list[0:], 
        my_int_list[1:], 
        my_int_list[2:], 
        my_int_list[3:], 
        my_int_list[4:], 
        my_int_list[5:], 
        my_int_list[6:], 
        my_int_list[7:], 
        my_int_list[8:], 
        my_int_list[9:], 
        my_int_list[10:], 
        my_int_list[11:], 
        my_int_list[12:]))

In case this takes up too much memory you could also use itertools.islice instead of the direct slicing with [idx:] .

Here is an implementation of your sliding window idea, modified so that it only applies to strings which contain no zeros:

def max_product(s,k):
    s = [int(d) for d in s]
    p = 1
    for d in s[:k]:
        p *= d
    m = p
    for i,d in enumerate(s[k:]):
        p *= d
        p //= s[i]
        if p > m: m = p
    return p

In the above s is a string of nonzero digits of length at least k ( k = 13 in your problem). It returns the largest product of k successive digits. The subtlety is in the way enumerate works. When you use enumerate on s[k:] the index, i , starts at 0 -- which is exactly the factor that you want to remove in the first pass through that loop.

To apply this to

data = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'

First split into chunks which contain no zeros and are at least 13 digits long:

chunks = [s for s in data.split('0') if len(s) >= 13]

There are 24 such chunks. To get the overall max, just take the max of the max of each chunk:

print(max(max_product(s,13) for s in chunks))

which does indeed print 23514624000

Your current code isn't working because it seems to be based on the wrong plan -- or at least on a plan that I do not fully understand. Here's a different way to think about the algorithm.

Imagine we have this number: 7316717 . And we are looking for the maximum product of 3 adjacent digits. We could solve the problem as follows. I'm hard-coding the result from each step, but you should be able to write Python code to compute each part.

  • Find all adjacent 3-digit sequences:

     seqs = [731, 316, 167, 671, 717] 
  • Compute their products:

     products = [21, 18, 42, 42, 49] 
  • Find their maximum.

     answer = max(products) 

I haven't checked your code and in which way it won't work.

But an easy way to solve your problem, is generating all the possibile slices with 13 adjacent numbers from your input data then find the product of their elements then find the maximum product of them all.

Here is a way to do it:

data = '7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'

def product(a):
    prod = 1
    for k in a:
        prod *= int(k)
    return prod

def max_adjacent_number(data, suit=13):
    return max(product(data[k:k+suit]) for k in range(len(data)) if '0' not in data[k:k+suit])


from time import time
start = time()
val = max_adjacent_number(data)
elapsed = time() - start
print("Solution: {0} \telapsed: {1:.5f}ms".format(val, elapsed*1000))

Output:

# Best time
Solution: 23514624000   elapsed: 1.31226ms

You can improve your code efficiency using list comprehension like this:

import time
n = str(x) #x is the long number
a = time.time()
result = max(reduce(lambda x, y: x * y, map(int, n[i:i+13])) for i in xrange(len(n)-12) if '0' not in n[i:i+13])
b = time.time()
print "Maximum adjacent numbers product: %d" % result
print "Time taken:", (b-a)*1000, "ms"

Output:

Maximum adjacent numbers product: 23514624000
Time taken: 4.34899330139 ms

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM