Find the greatest product of five consecutive digits in the 1000-digit number:
import time
num = '\
73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450'
biggest = 0
i = 1
while i < len(num):
one = int(num[i])
two = int(num[i+1])
thr = int(num[i+2])
fou = int(num[i+3])
fiv = int(num[i+4])
product = one*two*thr*fou*fiv
if product > biggest:
biggest = product
i += i+1
print(product)
start = time.time()
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")
This code gives me an answer of 7054, much too low, and should calculate many products along the way, but only calculates 9 of them. My question is: What is causing my code to deviate from its intended purpose and also, how can I optimize the part of the code calculating "one", "two", etc. in order to calculate the product?
There were several issues.
You were printing product not biggest. Make sure to print the right variable!
You were iterating through the length of the entire string when you should really just iterate in the range [0..len(num) - 4) so that you don't get an IndexError when you do your product calculation.
You were incrementing your i variable wrong. You want to increment it by 1 each turn so just do i += 1 or i = i + 1. The code i += i + 1 is equivalent to i = i + i + 1. I don't think you wanted to double i on every iteration of your while loop. :)
Sequences are 0-indexed in Python. This means when you are iterating through a set of indices, the first element is always at seq[0] and the elements continue until seq[n-1]. Therefore you should start your i variable at 0, not 1!
You were not measuring your time correctly. You want to have your start time be assigned to before all your code executes so that you can correctly measure elapsed time.
Here is your fixed code:
'''
Find the greatest product of five consecutive digits in the 1000-digit number
'''
import time
start = time.time()
num = '\
73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450'
biggest = 0
i = 0
while i < len(num) - 4:
one = int(num[i])
two = int(num[i+1])
thr = int(num[i+2])
fou = int(num[i+3])
fiv = int(num[i+4])
product = one*two*thr*fou*fiv
if product > biggest:
biggest = product
i = i + 1
print(biggest)
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")
Your problem is here:
i += i+1
You are walking through the list too fast. You should do this:
i += 1
I would write the code like this:
import operator
# Return the product of all the digits in `series` converted to integers
def numprod(series):
# Convert the series of digits into a list of integers
digits = [int(c) for c in series]
# This applies the multiplication operator to all the digits,
# starting with 1
return reduce(operator.__mul__, digits, 1)
# Produce every string of length 5
# This uses a generator but could just as easily use a list comprehension:
# numiter = [num[i : i + SERIES_SIZE] for i in range(len(num) - SERIES_SIZE + 1)]
SERIES_SIZE = 5
numiter = (num[i : i + SERIES_SIZE] for i in range(len(num) - SERIES_SIZE + 1))
# Calculate all the products
allnumprods = [numprod(series) for series in numiter]
# Find the maximum of all the products
print max(allnumprods)
A simpler way to calculate the product is this:
def numprod(series):
product = 1
for c in series:
product *= int(c)
return product
One can also use functional programing to simplify the problem considerably:
def foo():
max_product = 0
num = "string of input number"
for e,n in enumerate(num):
product = reduce((lambda x,y: x*y),map(int,(num[e:e+13])))
if product > max_product:
max_product = product
return max_product
give it a try!
The issue is here:
i += i+1
You are doubling i every time and adding 1 to it. So if i is 1, you make it 3. If it's 3, you make it 7. If it's 7, you make it 15, and so on. But this means your index is missing a lot of places, isn't it!
It is causing you to skip many positions in the number. You want to use:
i += 1
This just means add 1 to i.
Or you could do:
i = i+1
This means, set i equal to i+1.
import string
numbers=list()
fo=open("C:/python34/libs/maths2.txt","r+")
for eachline in fo:
for char in eachline:
if char.isdigit():
A=char
numbers.append(int(A))
print(numbers)
list1=list()
for i in range(0,len(numbers)-4):
x=numbers[i]*numbers[i+1]*numbers[i+2]*numbers[i+3]*numbers[i+4]
list1.append([x])
print(list1)
print(max(list1))
again this is not optimized but it works for 13 digits
import time
start_time = time.time()
num = "73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450"
i = 0
j = 0
k = 0
while i < len(num) - 13:
one = int(num[i])
two = int(num[i + 1])
three = int(num[i + 2])
four = int(num[i + 3])
five = int(num[i + 4])
six = int(num[i + 5])
seven = int(num[i + 6])
eight = int(num[i + 7])
nine = int(num[i + 8])
ten = int(num[i + 9])
eleven = int(num[i + 10])
twoelve = int(num[i + 11])
thirteen = int(num[i + 12])
j = one * two * three * four * five * six * seven * eight * nine * ten * eleven * twoelve * thirteen
i = i + 1
if k < j:
k = j
print(k)
print(time.time() - start_time," seconds")
# 8 Largest product in a series
from functools import reduce
the_num = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450"
the_num_lst = []
for n in the_num:
the_num_lst.append(int(n))
x = 0
y = reduce((lambda a, b: a * b), the_num_lst[x:x + 13])
while x < 1000 - 13:
x += 1
z = reduce((lambda a, b: a * b), the_num_lst[x:x + 13])
if z > y:
y = z
print(y)
My solution
s = '''7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450'''
t = list(s)
#len(t) = 1000
#t[::-1] = t[999]
r = []
q = 0
while q <= 999:
w = int(t[q])
r.append(w)
q += 1
a = 0
b = 1
c = 2
d = 3
e = 4
f = 5
g = 6
h = 7
i = 8
j = 9
k = 10
l = 11
m = 12
y = []
while m<=999:
n = r[a]*r[b]*r[c]*r[d]*r[e]*r[f]*r[g]*r[h]*r[i]*r[j]*r[k]*r[l]*r[m]
y.append(n)
a += 1
b += 1
c += 1
d+= 1
e+= 1
f+= 1
g+= 1
h+= 1
i+= 1
j+= 1
l+= 1
k+= 1
m+= 1
if m >= 1000:
break
print(y)
print(max(y))
One-liner:
from functools import reduce
def max_prod(x):
return max([reduce(lambda x, y: int(x) * int(y), (x[i:i+5])) for i in range(len(x)-5)])
The solutions on here iterate over the series and iterate over a window (sub-series) in each iteration, which make them very slow for large window sizes.
The solution below computes the product in each iteration by using the product from the previous iteration, so there's no need to re-compute most of it (saves a loop over each window). To do that, it uses deque from the built-in collections module to keep a running window that allows to drop elements from each window efficiently.
The basic idea is, in each iteration, divide the product from the previous iteration by the first number used in its computation and multiply it by the number in the current iteration - similar to moving the window one slot to the right.
The main difficulty is that any number multiplied by 0 is 0, so once 0 enters a window, the product of the remaining numbers are lost. To recover that, two separate products are kept in each iteration: prod (which is the true running product) and after_zero (which is the product of non-zero numbers after a 0), and after_zero is assigned back to prod once the window doesn't contain a zero anymore.
from collections import deque
def compute_window(new_digit, prod, no_zero_prod, window, old_digit=1):
# compute product for this window
prod = prod // old_digit * new_digit
# if the new digit is zero, restart everything (because 0*number=0)
if new_digit == 0:
window, prod, no_zero_prod = deque(), 0, 1
else:
window.append(new_digit)
no_zero_prod = no_zero_prod // old_digit * new_digit
return prod, no_zero_prod, window
def greatest_product(num, window_size):
# initialize variable
running_window = deque()
prod = after_zero = 1
# calculate the initial product
for d in num[: window_size]:
prod, after_zero, running_window = compute_window(int(d), prod, after_zero, running_window)
# max value to beat
max_so_far = prod
for d in num[window_size :]:
# in each iteration, if the window is full, pop the element that was first entered
current_window_size = len(running_window)
prev = running_window.popleft() if current_window_size == window_size else 1
# if a single element is missing from window, assign the after_zero value to prod
# (which allows us to use it for this round's product computation)
if current_window_size == window_size - 1:
prod = after_zero
# computations for this iteration
prod, after_zero, running_window = compute_window(int(d), prod, after_zero, running_window, prev)
# update max_so_far
if prod > max_so_far:
max_so_far = prod
return max_so_far
If num is an integer instead of a string, the following works in a very similar way; only, it starts from the end by iteratively dividing the integer by 10 to get the individual digits; so instead of moving the window to the right, it moves it to the left in each iteration.
def greatest_product(num, window_size):
n = num
prod = after_zero = 1
max_so_far = -1
running_window = deque()
while n:
n, r = divmod(n, 10)
current_window_size = len(running_window)
prev = running_window.popleft() if current_window_size == window_size else 1
if current_window_size == window_size - 1:
prod = after_zero
prod, after_zero, running_window = compute_window(r, prod, after_zero, running_window, prev)
# update max_so_far
if prod > max_so_far:
max_so_far = prod
return max_so_far
Output:
print(greatest_product(num, 13))
# 23514624000
To optimize the code, I think it is better to split the string by "0". Then find the product if the string length is greater than the adjacent number.
number = "73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450"
no_of_adjacent = 13
def find_greatest_product(num, adj):
greatest = 1
for i in range(adj):
greatest *= int(num[i])
prv_temp = greatest
for i in range(adj, len(num)):
temp = (prv_temp // int(num[i-adj])) * int(num[i])
prv_temp = temp
if (temp > greatest):
greatest = temp
return greatest
fractions = number.split("0")
greatest_product = 1
for frac in fractions:
if len(frac) >= no_of_adjacent:
temp = find_greatest_product(frac, no_of_adjacent)
if temp > greatest_product:
greatest_product = temp
print(greatest_product)
Related
I am trying to solve USACO's Milking Cows problem. The problem statement is here: https://train.usaco.org/usacoprob2?S=milk2&a=n3lMlotUxJ1
Given a series of intervals in the form of a 2d array, I have to find the longest interval and the longest interval in which no milking was occurring.
Ex. Given the array [[500,1200],[200,900],[100,1200]], the longest interval would be 1100 as there is continuous milking and the longest interval without milking would be 0 as there are no rest periods.
I have tried looking at whether utilizing a dictionary would decrease run times but I haven't had much success.
f = open('milk2.in', 'r')
w = open('milk2.out', 'w')
#getting the input
farmers = int(f.readline().strip())
schedule = []
for i in range(farmers):
schedule.append(f.readline().strip().split())
#schedule = data
minvalue = 0
maxvalue = 0
#getting the minimums and maximums of the data
for time in range(farmers):
schedule[time][0] = int(schedule[time][0])
schedule[time][1] = int(schedule[time][1])
if (minvalue == 0):
minvalue = schedule[time][0]
if (maxvalue == 0):
maxvalue = schedule[time][1]
minvalue = min(schedule[time][0], minvalue)
maxvalue = max(schedule[time][1], maxvalue)
filled_thistime = 0
filled_max = 0
empty_max = 0
empty_thistime = 0
#goes through all the possible items in between the minimum and the maximum
for point in range(minvalue, maxvalue):
isfilled = False
#goes through all the data for each point value in order to find the best values
for check in range(farmers):
if point >= schedule[check][0] and point < schedule[check][1]:
filled_thistime += 1
empty_thistime = 0
isfilled = True
break
if isfilled == False:
filled_thistime = 0
empty_thistime += 1
if (filled_max < filled_thistime) :
filled_max = filled_thistime
if (empty_max < empty_thistime) :
empty_max = empty_thistime
print(filled_max)
print(empty_max)
if (filled_max < filled_thistime):
filled_max = filled_thistime
w.write(str(filled_max) + " " + str(empty_max) + "\n")
f.close()
w.close()
The program works fine, but I need to decrease the time it takes to run.
A less pretty but more efficient approach would be to solve this like a free list, though it is a bit more tricky since the ranges can overlap. This method only requires looping through the input list a single time.
def insert(start, end):
for existing in times:
existing_start, existing_end = existing
# New time is a subset of existing time
if start >= existing_start and end <= existing_end:
return
# New time ends during existing time
elif end >= existing_start and end <= existing_end:
times.remove(existing)
return insert(start, existing_end)
# New time starts during existing time
elif start >= existing_start and start <= existing_end:
# existing[1] = max(existing_end, end)
times.remove(existing)
return insert(existing_start, end)
# New time is superset of existing time
elif start <= existing_start and end >= existing_end:
times.remove(existing)
return insert(start, end)
times.append([start, end])
data = [
[500,1200],
[200,900],
[100,1200]
]
times = [data[0]]
for start, end in data[1:]:
insert(start, end)
longest_milk = 0
longest_gap = 0
for i, time in enumerate(times):
duration = time[1] - time[0]
if duration > longest_milk:
longest_milk = duration
if i != len(times) - 1 and times[i+1][0] - times[i][1] > longest_gap:
longes_gap = times[i+1][0] - times[i][1]
print(longest_milk, longest_gap)
As stated in the comments, if the input is sorted, the complexity could be O(n), if that's not the case we need to sort it first and the complexity is O(nlog n):
lst = [ [300,1000],
[700,1200],
[1500,2100] ]
from itertools import groupby
longest_milking = 0
longest_idle = 0
l = sorted(lst, key=lambda k: k[0])
for v, g in groupby(zip(l[::1], l[1::1]), lambda k: k[1][0] <= k[0][1]):
l = [*g][0]
if v:
mn, mx = min(i[0] for i in l), max(i[1] for i in l)
if mx-mn > longest_milking:
longest_milking = mx-mn
else:
mx = max((i2[0] - i1[1] for i1, i2 in zip(l[::1], l[1::1])))
if mx > longest_idle:
longest_idle = mx
# corner case, N=1 (only one interval)
if len(lst) == 1:
longest_milking = lst[0][1] - lst[0][0]
print(longest_milking)
print(longest_idle)
Prints:
900
300
For input:
lst = [ [500,1200],
[200,900],
[100,1200] ]
Prints:
1100
0
from pylab import *
no_steps = 10000
number = random()
position = zeros(no_steps)
position[0] = 0
time = zeros(no_steps)
time[0] = 0
for i in range(1, no_steps):
time[i] = time[i-1] + 1
if number >= 0.5:
position[i] = position[i-1] + 1
number = random()
else:
position[i] = position[i-1] - 1
number = random()
plot(time, position)
number2 = random()
position2 = zeros(no_steps)
position2[0] = 0
time2 = zeros(no_steps)
time2[0] = 0
for t2 in range(1, no_steps):
time2[t2] = time[t2-1] + 1
if number2 >= 0.5:
position2[t2] = position2[t2-1] + 1
number2 = random()
else:
position2[t2] = position[t2-1] - 1
number2 = random()
plot(time2,position2)
This is supposed to generate random walks by generating a random number each time and checking the conditions. Therefore I assumed that if it works for one walk I can just add more of the same and put them all on the same graph at the end. However, apparently that's not how this works and the graphs that do end up being plotted are extremely similar with the difference in the positions being one of -2 for some reason. The code if I run the blocks separately from their own program will generate two completely different walks, it's just when I put them together that it stops working as intended. What exactly am I missing?
You've accidentally reused variables from the first plot:
for t2 in range(1, no_steps):
time2[t2] = time[t2-1] + 1
^^^^^ ^^^^
if number2 >= 0.5:
position2[t2] = position2[t2-1] + 1
number2 = random()
else:
position2[t2] = position[t2-1] - 1
^^^^^^^^^ ^^^^^^^^
number2 = random()
plot(time2,position2)
I would generate the random walk with a function so you don't have to worry about renaming variables like this:
import numpy
from pylab import *
no_steps = 10000
def random_walk(no_steps):
# 2 * [0, 1] - 1 -> [0, 2] - 1 -> [-1, 1]
directions = 2 * numpy.random.randint(0, 2, size=(1, no_steps)) - 1
positions = numpy.cumsum(directions)
positions -= positions[0] # To make it start from zero
return positions
time1 = numpy.arange(0, no_steps)
plot(time1, random_walk(no_steps))
savefig('1.png')
clf()
time2 = numpy.arange(0, no_steps)
plot(time2, random_walk(no_steps))
savefig('2.png')
For this question http://www.spoj.com/problems/ACPC10D/ on SPOJ, I wrote a python solution as below:
count = 1
while True:
no_rows = int(raw_input())
if no_rows == 0:
break
grid = [[None for x in range(3)] for y in range(2)]
input_arr = map(int, raw_input().split())
grid[0][0] = 10000000
grid[0][1] = input_arr[1]
grid[0][2] = input_arr[1] + input_arr[2]
r = 1
for i in range(0, no_rows-1):
input_arr = map(int, raw_input().split())
_r = r ^ 1
grid[r][0] = input_arr[0] + min(grid[_r][0], grid[_r][1])
grid[r][1] = input_arr[1] + min(min(grid[_r][0], grid[r][0]), min(grid[_r][1], grid[_r][2]))
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[r][1]), grid[_r][2])
r = _r
print str(count) + ". " + str(grid[(no_rows -1) & 1][1])
count += 1
The above code exceeds time limit. However, when I change the line
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[r][1]), grid[_r][2])
to
grid[r][2] = input_arr[2] + min(min(grid[_r][1], grid[_r][2]), grid[r][1])
the solution is accepted. If you notice the difference, the first line compares, grid[_r][1], grid[r][1] for minimum (i.e. the row number are different) and second line compares grid[_r][1], grid[_r][2] for minimum(i.e. the row number are same)
This is a consistent behaviour. I want to understand, how python is processing those two lines - so that one results in exceeding time limit, while other is fine.
I started coding a month ago on Python and so far i've done the other 7 Euler problems but have been stuck on this one for a week now, here's the problem statement:
"The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.
Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?"
and here's the code i've written so far:
num = '\
73167176531330624919225119674426574742355349194934\
96983520312774506326239578318016984801869478851843\
85861560789112949495459501737958331952853208805511\
12540698747158523863050715693290963295227443043557\
66896648950445244523161731856403098711121722383113\
62229893423380308135336276614282806444486645238749\
30358907296290491560440772390713810515859307960866\
70172427121883998797908792274921901699720888093776\
65727333001053367881220235421809751254540594752243\
52584907711670556013604839586446706324415722155397\
53697817977846174064955149290862569321978468622482\
83972241375657056057490261407972968652414535100474\
82166370484403199890008895243450658541227588666881\
16427171479924442928230863465674813919123162824586\
17866458359124566529476545682848912883142607690042\
24219022671055626321111109370544217506941658960408\
07198403850962455444362981230987879927244284909188\
84580156166097919133875499200524063689912560717606\
05886116467109405077541002256983155200055935729725\
71636269561882670428252483600823257530420752963450'
digit = str(num)
def find(s, ch):
return [i for i, ltr in enumerate(s) if ltr == ch]
lst = find(digit, "0")
placeholder = "0"
series_sum = "0"
for element in lst:
total = 1
value = digit[int(placeholder):element]
if len(value) == 13:
for i in value:
total *= int(i)
if total > int(series_sum):
series_sum = str(total)
elif len(value) > 13:
c = 0
c2 = 13
counter = len(value) - 13
while counter > 0:
for i in value[c:c2]:
total *= int(i)
if total > int(series_sum):
series_sum = str(total)
counter -= 1
c += 1
c2 += 1
placeholder = str(element)
print series_sum
my approach here was to convert the number into a string, and make a list containing the index of the 0's, then iterating through the string and checking if there were at least 13 numbers between 0's, and do the math from there, but so far i've only managed to get it to work on the first 13 numbers, i think the bug might be in the part that says: elif len(value) > 13:.
also, any advice on which type of object (lists, strings, ints, etc.)to use for this kind of procedures and why is greatly appreciated.
edit: Solved it!, thanks a lot john, here's the code i used:
series_sum = 0
for i in range(len(num)):
total = 1
digits = num[i: i + 13]
for i in digits:
total *= int(i)
if total > series_sum:
series_sum = total
print series_sum
i now see that i wasn't being efficient at all, at least i know now
You don't need the variable digit as num is already a string. To get all the chunks of 13 consecutive digits from num you can use a loop like this
for i in range(len(num)):
digits = num[i: i + 13]
You'll get some shorter strings a the end, but they won't affect your quest to find the maximum product
you can remove one for loop .... but for this imports are needed
from functools import reduce
from operator import mul
total = reduce(mul, map(int,digits), 1)
with functools it is faster, than with for loop.
test for 1000 runs
with for loop 7.484771039336005
with functools 6.376082365216808
(Python) Given two numbers A and B. I need to find all nested "groups" of numbers:
range(2169800, 2171194)
leading numbers: 21698XX, 21699XX, 2170XX, 21710XX, 217110X, 217111X,
217112X, 217113X, 217114X, 217115X, 217116X, 217117X, 217118X, 2171190X,
2171191X, 2171192X, 2171193X, 2171194X
or like this:
range(1000, 1452)
leading numbers: 10XX, 11XX, 12XX, 13XX, 140X, 141X, 142X, 143X,
144X, 1450, 1451, 1452
Harder than it first looked - pretty sure this is solid and will handle most boundary conditions. :) (There are few!!)
def leading(a, b):
# generate digit pairs a=123, b=456 -> [(1, 4), (2, 5), (3, 6)]
zip_digits = zip(str(a), str(b))
zip_digits = map(lambda (x,y):(int(x), int(y)), zip_digits)
# this ignores problems where the last matching digits are 0 and 9
# leading (12000, 12999) is same as leading(12, 12)
while(zip_digits[-1] == (0,9)):
zip_digits.pop()
# start recursion
return compute_leading(zip_digits)
def compute_leading(zip_digits):
if(len(zip_digits) == 1): # 1 digit case is simple!! :)
(a,b) = zip_digits.pop()
return range(a, b+1)
#now we partition the problem
# given leading(123,456) we decompose this into 3 problems
# lows -> leading(123,129)
# middle -> leading(130,449) which we can recurse to leading(13,44)
# highs -> leading(450,456)
last_digits = zip_digits.pop()
low_prefix = reduce(lambda x, y : 10 * x + y, [tup[0] for tup in zip_digits]) * 10 # base for lows e.g. 120
high_prefix = reduce(lambda x, y : 10 * x + y, [tup[1] for tup in zip_digits]) * 10 # base for highs e.g. 450
lows = range(low_prefix + last_digits[0], low_prefix + 10)
highs = range(high_prefix + 0, high_prefix + last_digits[1] + 1)
#check for boundary cases where lows or highs have all ten digits
(a,b) = zip_digits.pop() # pop last digits of middle so they can be adjusted
if len(lows) == 10:
lows = []
else:
a = a + 1
if len(highs) == 10:
highs = []
else:
b = b - 1
zip_digits.append((a,b)) # push back last digits of middle after adjustments
return lows + compute_leading(zip_digits) + highs # and recurse - woohoo!!
print leading(199,411)
print leading(2169800, 2171194)
print leading(1000, 1452)
def foo(start, end):
index = 0
is_lower = False
while index < len(start):
if is_lower and start[index] == '0':
break
if not is_lower and start[index] < end[index]:
first_lower = index
is_lower = True
index += 1
return index-1, first_lower
start = '2169800'
end = '2171194'
result = []
while int(start) < int(end):
index, first_lower = foo(start, end)
range_end = index > first_lower and 10 or int(end[first_lower])
for x in range(int(start[index]), range_end):
result.append(start[:index] + str(x) + 'X'*(len(start)-index-1))
if range_end == 10:
start = str(int(start[:index])+1)+'0'+start[index+1:]
else:
start = start[:index] + str(range_end) + start[index+1:]
result.append(end)
print "Leading numbers:"
print result
I test the examples you've given, it is right. Hope this will help you
This should give you a good starting point :
def leading(start, end):
leading = []
hundreds = start // 100
while (end - hundreds * 100) > 100:
i = hundreds * 100
leading.append(range(i,i+100))
hundreds += 1
c = hundreds * 100
tens = 1
while (end - c - tens * 10) > 10:
i = c + tens * 10
leading.append(range(i, i + 10))
tens += 1
c += tens * 10
ones = 1
while (end - c - ones) > 0:
i = c + ones
leading.append(i)
ones += 1
leading.append(end)
return leading
Ok, the whole could be one loop-level deeper. But I thought it might be clearer this way. Hope, this helps you...
Update :
Now I see what you want. Furthermore, maria's code doesn't seem to be working for me. (Sorry...)
So please consider the following code :
def leading(start, end):
depth = 2
while 10 ** depth > end : depth -=1
leading = []
const = 0
coeff = start // 10 ** depth
while depth >= 0:
while (end - const - coeff * 10 ** depth) >= 10 ** depth:
leading.append(str(const / 10 ** depth + coeff) + "X" * depth)
coeff += 1
const += coeff * 10 ** depth
coeff = 0
depth -= 1
leading.append(end)
return leading
print leading(199,411)
print leading(2169800, 2171194)
print leading(1000, 1453)
print leading(1,12)
Now, let me try to explain the approach here.
The algorithm will try to find "end" starting from value "start" and check whether "end" is in the next 10^2 (which is 100 in this case). If it fails, it will make a leap of 10^2 until it succeeds. When it succeeds it will go one depth level lower. That is, it will make leaps one order of magnitude smaller. And loop that way until the depth is equal to zero (= leaps of 10^0 = 1). The algorithm stops when it reaches the "end" value.
You may also notice that I have the implemented the wrapping loop I mentioned so it is now possible to define the starting depth (or leap size) in a variable.
The first while loop makes sure the first leap does not overshoot the "end" value.
If you have any questions, just feel free to ask.