count '9's from 1 to n python optimization - python

def count_nines(n):
x = list(map(str,range(n + 1)))
count = 0
for i in x:
c = i.count('9')
count += c
return count
Execution Timed Out (12000 ms)
How can i optimize this code ?

Here's some working code (I tested it on some not too big numbers, and it returns the same results as yours) based on my comment:
def count_nines(n):
if n==0:
return 0
k = len(str(n))-1
leading_digit, remainder = divmod(n, 10**k) # Thanks #Stef for this optimization
# Number of nines in numbers from 1 to leading_digit * 10**k - 1
count1 = leading_digit * k*10**(k-1)
# If the leading_digit is 9, number of times it appears
# (in numbers from 9 * 10**k to n)
count2 = remainder+1 if leading_digit==9 else 0
# Number of nines in remainder
count3 = count_nines(remainder)
# Total number of nines
return int(count1 + count2 + count3)
Explanations
For starters, the numbers of nines (shortened as c9() hereafter) in 1-10^k is k * 10^(k-1); this is easy to prove by recurrence, but I'll just explain on an example:
assuming c9(1000) = 300, the number of nines in the xxx part of numbers 0xxx, 1xxx ... 9xxx is equal to 10 * 300; add to that the number of 9 in 9xxx is 1000 (from 9000 to 9999), which yields c9(10000) = 10*300 + 1000 = 4000 .
Now imagine you want c9(7935) : you have 7 * 300 nines in numbers 1-7000, then 9*20 nines in numbers 7 000 to 7 900, then 36 leading nines in number 900 to 935, then ...
Example
count_nines(9254287593789050756)
Out[12]: 16880680640899572416

Related

Calculate if the train can pass over the bridge

The bridge's length and load-carrying capacity are known. Each of the train's wagons has a given length and weight. Program must determine whether the train can safely cross the bridge, i.e. whether the total weight of wagons that will simultaneously be on the bridge exceeds the bridge's carrying capacity.
To be safe, if any part of a wagon is on the bridge, we will count the entire weight of that wagon in computing the total weight at that moment.
Input format:
The first input line contains two integers: the length of the bridge and its carrying capacity.
The following input line(s) contain a sequence of pairs indicating the length and weight of each wagon in sequence. Each wagon's length and weight will always appear on the same line. Each input line will be at most 200 characters long.
Output:
If the train can safely cross the bridge, write the number -1. Otherwise, write the number of the first wagon that will cause the weight to exceed the bridge's carrying capacity. Wagons are numbered from 1.
Sample input #1:
10 100
10 90 10 10 9 80 1 10 9 10 9 80
5 10 5 10
1 10 1 10 1 10 1 10 1 40
Output:
-1
Sample input #2:
7 20
3 4 3 5
3 5 3 7
3 7 3 7
3 6
Output:
4
Some more examples:
Input:
5 10
5 5 5 5 5 5 5 5 5 5 5 100 5 100 5 100
Output:
6
My code is
def bridge(p, k, n):
if p or n == 0:
print(-1)
else:
wagon_length(lenght, wagon_lenght, p, n, k)
def wagon_length(lenght, wagon_lenght, p, n, k):
lenght = lenght - wagon_lenght[n]
wagon_lenght.remove(wagon_lenght[n])
k = k+1
if lenght > 0:
n = n-1
wagon_length(lenght, wagon_lenght, p, k, n)
elif lenght <= 0:
n = n-k
wagon_mass(weight, wagon_weight, p, k, n)
def wagon_mass(weight, wagon_weight, p, k, n):
res = sum(wagon_weight[-k:])
weight = weight - res
p = p - k
wagon_weight.remove(wagon_weight[p])
k = 0
if weight < 0:
print(p)
if weight >= 0:
bridge(p, k, n)
a = input()
lines = []
while True:
line = input()
if line:
lines.append(line)
else:
break
text = '\n'.join(lines)
bbh = [int(t) for t in text.split()]
arr = [int(d) for d in a.split()]
k = 0
weight = arr[1]
lenght = arr[0]
wagon_weight = bbh[1::2]
wagon_lenght = bbh[0::2]
n = len(wagon_lenght)-1
p = len(wagon_weight)-1
bridge(p, k, n)
I tried to make it so that every time a wagon hits the bridge, we add one to the number k, which means the number of wagons that are currently on the bridge, and then just calculate the total weight of this number of wagons and subtract them from the maximum values ​​- if the weight is greater than or equal to zero, then these wagons have passed.
But the mistake of my code is that when operations are performed with list, instead of the last wagons (I go from the last to the first), it deletes the smallest values ​​and the code does not work as I intended
You could convert the sequence of wagons into sequences of added and removed weights for each meter of the train's length. The two sequences would be offset by the length of the bridge so that you can add them together and get the total load on the bridge every time the train moves by one meter. The accumulate function from itertools can help with computing the total load at each meter:
from itertools import accumulate
def support(bridge,capacity,wagons):
index = [i for i,(wl,_) in enumerate(wagons,1) for _ in range(wl)]
start = accumulate(w for wl,ww in wagons
for w in [ww]+[0]*(wl-1))
end = accumulate(-w for wl,ww in [(bridge,0)]+wagons
for w in [0]*(wl-1)+[ww])
load = map(sum,zip(start,end))
return next((index[m] for m,w in enumerate(load) if w>capacity),-1)
Output:
bridge = 10
capacity = 100
wagons = [(10,90),(10,10),(9,80),(1,10),(9,10),(9,80),(5,10),(5,10),
(1,10),(1,10),(1,10),(1,10),(1,40)]
print(support(bridge,capacity,wagons)) # -1
bridge = 7
capacity = 20
wagons = [(3,4),(3,5),(3,5),(3,7),(3,7),(3,7),(3,6)]
print(support(bridge,capacity,wagons)) # 6
bridge = 5
capacity = 10
wagons = [(5,5),(5,5),(5,5),(5,5),(5,5),(5,100),(5,100),(5,100)]
print(support(bridge,capacity,wagons)) # 6
For example:
bridge = 7
capacity = 20
wagons = [(3,4),(3,5),(3,5),(3,7),(3,7),(3,7),(3,6)]
index will contain the id of the wagon that is added on the bridge at the corresponding meter position
start is the cumulative sum of wagon weights for wagons that are added on the bridge
end is the cumulative sum of wagon weights for wagons that leave the bridge (negative)
load is the actual load (added - leaving) on the bridge when the corresponding meter of the train reaches the bridge.
After the last wagon is added on the bridge, is is not necessary to further check capacity as the load will only decrease thereafter
...
index 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 6 6 6 7 7 7
enter 4 0 0 5 0 0 5 0 0 7 0 0 7 0 0 7 0 0 6 0 0
(leaving) 1 1 1 2 2 2 3 3 3 4 4 4 ...
leave 0 0 0 0 0 0 0 0 0 -4 0 0 -5 0 0 -5 0 0 -7 0 0 ...
start 4 4 4 9 9 9 14 14 14 21 21 21 28 28 28 35 35 35 41 41 41
end 0 0 0 0 0 0 0 0 0 -4 -4 -4 -9 -9 -9 -14 -14 -14 -21 -21 -21 ...
load 4 4 4 9 9 9 14 14 14 17 17 17 19 19 19 21 21 21 20 20 20
^
Overload here _______|
without libraries (same logic)
def support(bridge,capacity,wagons):
index = (i for i,(wl,_) in enumerate(wagons,1) for _ in range(wl))
enter = (w for wl,ww in wagons for w in [ww]+[0]*(wl-1))
leave = (w for wl,ww in [(bridge,0)]+wagons for w in [0]*(wl-1)+[ww])
load = 0 # current load on bridge
for i,more,less in zip(index,enter,leave): # examine each meter
load += more-less # track total weigth
if load>capacity: return i # detect overload
return -1
memory efficient solution using a queue
def support(bridge,capacity,wagons):
onBridge = deque([(bridge,0)]) # wagons/weights on bridge
load = 0 # current load
for i,(wl,ww) in enumerate(wagons,1):
load += ww # combined load (continuous)
if load>capacity: return i # check overload
onBridge.append((wl,ww)) # add wagon on bridge
while wl>0: # advance to end of wagon
bl,bw = onBridge[0]
if wl>=bl: # reduce load for exiting
load -= onBridge.popleft()[1]
else: # reduce length for partial
onBridge[0] = (bl-wl,bw)
wl -= bl # up to new wagon's length
return -1
I haven't proved my solution. There might be some redundant code.
My code will return the index (0 based indexing) of 1st wagon which will cause the issue if you want the last just update the recursion:
my code will return -1 if bridge is not destroyed.
my code will return (index,'s') means the partial wagon at start will cause the destruction
my code will return (index,'e') means the partial wagon at end will cause the destruction
my code will return (index,'f') means the full wagon at start will cause the destruction
My code :
"""
- either wagon is fully on the bridge
- or partially placed on the bridge
- if partially place on the bridge:
* wagon is at starting point
* wagon is at last point
"""
import sys
sys.setrecursionlimit(10**8)
def move(wagonList, n , wagon , maxL, i, counter):
weight = wagon[1]
for j in range(i, n if counter > 0 else -1, counter):
if((maxL - wagonList[j][0]) <= 0):
weight += wagonList[j][1]
break
maxL -= wagonList[j][0]
weight += wagonList[j][1]
return weight
def moveCombo(wagonList, n , w , maxL, i,j):
if(i < 0 or j >= n or maxL <= 0):
return w
#return max(moveCombo(wagonList, n , w+wagonList[j][1] , maxL-wagonList[j][0], i,j+1),moveCombo(wagonList, n , w+wagonList[i][1] , maxL-wagonList[i][0], i-1,j))
return max(moveCombo(wagonList, n , w+wagonList[j][1] , maxL-wagonList[j][0], i,j+1),
max(moveCombo(wagonList, n , w+wagonList[i][1] , maxL-wagonList[i][0], i-1,j),
moveCombo(wagonList, n , w+wagonList[j][1]+wagonList[i][1] , maxL-wagonList[j][0]-wagonList[i][0], i-1,j+1)
))
def Gwagon(wagonList, n , maxL, maxW):
res = []
for i in range(n):
wagon = wagonList[i]
end = move(wagonList, n, wagon, maxL, i-1, -1)
start = move(wagonList, n, wagon, maxL, i+1, 1)
full = moveCombo(wagonList, n , wagon[1] , maxL-wagon[0], i-1, i+1)
if(start > maxW):
res.append((i,'s'))
if(end > maxW):
res.append((i,'e'))
if(full > maxW):
res.append((i,'f'))
if(res):
break
return res
def result(wagonList,n,maxL,maxW):
res = Gwagon(wagonList,n,maxL,maxW)
if(res):
print(*res)
else:
print(-1)
wagonList=[(10,90),(10,10),(9,80),(1,10),(9,10),(9,80),(5,10),(5,10),(1,10),(1,10),(1,10),(1,10),(1,40)]
result(wagonList,13,10,100)
wagonList=[(3,4),(3,5),(3,5),(3,7),(3,7),(3,7),(3,6)]
result(wagonList,7,7,20)
My Output:
-1
(0, 's')
our case 1 the bridge will not be destroyed so -1.
our case 2 the bridge will be destroyed, 1st wagon will be wagon no-1 {4,5,5,7}. wagon -1 will be the starting point and bridge will be destroyed if wagon is partial on the bridge.
New Code:
"""
- either wagon is fully on the bridge
- or partially placed on the bridge
- if partially place on the bridge:
* wagon is at starting point
* wagon is at last point
"""
import sys
sys.setrecursionlimit(10**8)
def move(wagonList, n , wagon , maxL, i, counter):
weight = wagon[1]
obj = (weight,i-counter)
for j in range(i, n if counter > 0 else -1, counter):
if((maxL - wagonList[j][0]) <= 0):
weight += wagonList[j][1]
obj = (weight, j)
break
maxL -= wagonList[j][0]
weight += wagonList[j][1]
return obj
def moveCombo(wagonList, n , w , maxL, i,j, maxW):
if(i < 0 or j >= n or maxL <= 0 or maxW < w):
return (w,j-1)
o1 = moveCombo(wagonList, n , w+wagonList[j][1] , maxL-wagonList[j][0], i,j+1, maxW)
o2 = moveCombo(wagonList, n , w+wagonList[i][1] , maxL-wagonList[i][0], i-1,j ,maxW)
o3 = moveCombo(wagonList, n , w+wagonList[j][1]+wagonList[i][1] , maxL-wagonList[j][0]-wagonList[i][0], i-1,j+1, maxW)
res = (0,n+1)
if(o1[0] > maxW):
res = o1
if(o2[0] > maxW):
if(res[1] > o2[1]):
res = o2
if(o3[0] > maxW):
if(res[1] > o3[1]):
res = o3
return res
def Gwagon(wagonList, n , maxL, maxW):
res = []
for i in range(n):
wagon = wagonList[i]
end = move(wagonList, n, wagon, maxL, i-1, -1)
start = move(wagonList, n, wagon, maxL, i+1, 1)
full = moveCombo(wagonList, n , wagon[1] , maxL-wagon[0], i-1, i+1, maxW)
if(start[0] > maxW):
res.append((start[1],'s'))
if(end[0] > maxW):
res.append((end[1],'e'))
if(full[0] > maxW):
res.append((full[1],'f'))
if(res):
break
return res
def result(wagonList,n,maxL,maxW):
res = Gwagon(wagonList,n,maxL,maxW)
if(res):
res.sort()
print(res[0][0]+1)
else:
print(-1)
wagonList=[(10,90),(10,10),(9,80),(1,10),(9,10),(9,80),(5,10),(5,10),(1,10),(1,10),(1,10),(1,10),(1,40)]
result(wagonList,13,10,100)
wagonList=[(3,4),(3,5),(3,5),(3,7),(3,7),(3,7),(3,6)]
result(wagonList,7,7,20)
OUTPUT:
-1
4
To avoid excessive memory use, you should not go for a solution where each unit of length is checked (like each meter if the unit if measure is meter). Instead go through the process of adding wagons at the end and removing them from the start.
As the weight of a wagon also counts when it is only touching the bridge, it will be useful to keep track of the the length and load with the following definitions:
length: represents the total length of a range of wagons that fit entirely on the bridge
load: represents the total weight of a range of wagons where the first and last wagon might not be completely on the bridge.
I would adapt the loading of data such that you don't need to zip to lists. Instead keep each wagon's length and weight together in a tuple. I would promote the use of named tuples here, since that improves the readability of the code.
As both the bridge and each wagon have a length and something that relates to weight, I would use the same named tuple class for both.
Here is the proposed code:
from collections import namedtuple
# Use named tuple to improve readability of the code
Item = namedtuple("Item", "length, weight")
def support(bridge, wagons):
# Deal with boundary cases
if not bridge.length or not wagons:
return -1
# initialise the total length of wagons that are completely on the bridge
length = 0
# .... and the total weight of wagons that touch the bridge
load = wagons[0].weight
# Some more boundary cases
if load > bridge.weight:
return 1
if len(wagons) == 1:
return -1
load += wagons[1].weight
if load > bridge.weight:
return 2
# The following loop has this invariant:
# load = sum( wagon.weight for wagon in wagons[start-1:end+1] )
# length = sum ( wagon.length for wagon in wagons[start:end] )
start = 1
for end in range(1, len(wagons) - 1):
# Remove first wagon(s) as long there is no room for the next wagon to
# be partly on the bridge while also the first is still partly on the bridge
while length + wagons[end].length >= bridge.length:
load -= wagons[start - 1].weight
length -= wagons[start].length
start += 1
# Now there is room for the next wagon...
length += wagons[end].length
load += wagons[end + 1].weight
if load > bridge.weight: # Exceeded the capacity of the bridge
return end + 2
return -1
# Helper functions to parse the input
def read_words_until_empty_line():
line = input()
while line:
yield from line.split()
line = input()
def words_to_items(words):
it = map(int, words)
for length in it:
yield Item(length, next(it))
# Driver code
bridge, *wagons = words_to_items(read_words_until_empty_line())
print(support(bridge, wagons))

Repeatedly adding digits of a number until the output has a single digit

I have a two digits number (e.g. 29) ) and wish to further reduce it to a single digit. How can I do such in python? Shall I use the function inside the while loop ?
e.g.
29 -> 11 -> 2
result:
[29,11,2]
x=input('Input digit: ')
result=0
box=[]
def add_two(x):
bz=[]
for i in str(x):
bz.append(int(i))
s=sum(bz)
return s
box=[]
a=0
while len(str(x))>1:
IIUC, you want to reduce a two digit number (29) into a single digit number by performing addition of the tens and units, repeatedly until the number is smaller than 10.
NB. I am using integers here, if you start from a string, first convert to int: x = int(x)
Let's use divmod by 10 to get the two components:
divmod(29, 10)
# 2, 9
and sum them:
sum(divmod(29, 10))
# 11
Now that we have the logic, let's repeat it:
x = 29
def reduce(x):
return sum(divmod(x,10))
while x>9:
x = reduce(x)
print(x)
# 2 # 2+9 -> 11 ; 1+1 -> 2
as a single function
def reduce_until(x):
while x>9:
x = sum(divmod(x,10))
return x
reduce_until(29)
# 2
generic function for an input of any size:
def reduce_until(x):
while x>9:
total = 0
while x>0:
x,r = divmod(x, 10)
total += r
x = total
return x
reduce_until(56789)
# 56789 -> 35 -> 8
reduce_until(99999999999992)
# 99999999999992 -> 119 -> 11 -> 2
import math
dob_d = 29
while not (0 <= dob_d <= 9):
n = 0
for i in range(math.ceil(math.log10(dob_d))):
n += int(dob_d / (10 ** i) % 10)
dob_d = n
print(dob_d)

any tip to improve performance when using nested loops with python

so, I had this exercise where I would receive a list of integers and had to find how many sum pairs were multiple to 60
example:
input: list01 = [10,90,50,40,30]
result = 2
explanation: 10 + 50, 90 + 30
example2:
input: list02 = [60,60,60]
result = 3
explanation: list02[0] + list02[1], list02[0] + list02[2], list02[1] + list02[2]
seems pretty easy, so here is my code:
def getPairCount(numbers):
total = 0
cont = 0
for n in numbers:
cont+=1
for n2 in numbers[cont:]:
if (n + n2) % 60 == 0:
total += 1
return total
it's working, however, for a big input with over 100k+ numbers is taking too long to run, and I need to be able to run in under 8 seconds, any tips on how to solve this issue??
being with another lib that i'm unaware or being able to solve this without a nested loop
Here's a simple solution that should be extremely fast (it runs in O(n) time). It makes use of the following observation: We only care about each value mod 60. E.g. 23 and 143 are effectively the same.
So rather than making an O(n**2) nested pass over the list, we instead count how many of each value we have, mod 60, so each value we count is in the range 0 - 59.
Once we have the counts, we can consider the pairs that sum to 0 or 60. The pairs that work are:
0 + 0
1 + 59
2 + 58
...
29 + 31
30 + 30
After this, the order is reversed, but we only
want to count each pair once.
There are two cases where the values are the same:
0 + 0 and 30 + 30. For each of these, the number
of pairs is (count * (count - 1)) // 2. Note that
this works when count is 0 or 1, since in both cases
we're multiplying by zero.
If the two values are different, then the number of
cases is simply the product of their counts.
Here's the code:
def getPairCount(numbers):
# Count how many of each value we have, mod 60
count_list = [0] * 60
for n in numbers:
n2 = n % 60
count_list[n2] += 1
# Now find the total
total = 0
c0 = count_list[0]
c30 = count_list[30]
total += (c0 * (c0 - 1)) // 2
total += (c30 * (c30 - 1)) // 2
for i in range(1, 30):
j = 60 - i
total += count_list[i] * count_list[j]
return total
This runs in O(n) time, due to the initial one-time pass we make over the list of input values. The loop at the end is just iterating from 1 through 29 and isn't nested, so it should run almost instantly.
Below is a translation of Tom Karzes's answer but using numpy. I benchmarked it and it is only faster if the input is already a numpy array, not a list. I still want to write it here because it nicely shows how loops in python can be one-liners in numpy.
def get_pairs_count(numbers, /):
# Count how many of each value we have, modulo 60.
numbers_mod60 = np.mod(numbers, 60)
_, counts = np.unique(numbers_mod60, return_counts=True)
# Now find the total.
total = 0
c0 = counts[0]
c30 = counts[30]
total += (c0 * (c0 - 1)) // 2
total += (c30 * (c30 - 1)) // 2
total += np.dot(counts[1:30:+1], counts[59:30:-1]) # Notice the slicing indices used.
return total

python - print squares of numbers which are palindromes : improve efficiency

I have an assignment to do. The problem is something like this. You give a number, say x. The program calculates the square of the numbers starting from 1 and prints it only if it's a palindrome. The program continues to print such numbers till it reaches the number x provided by you.
I have solved the problem. It works fine for uptil x = 10000000. Works fine as in executes in a reasonable amount of time. I want to improve upon the efficiency of my code. I am open to changing the entire code, if required. My aim is to make a program that could execute 10^20 within around 5 mins.
limit = int(input("Enter a number"))
def palindrome(limit):
count = 1
base = 1
while count < limit:
base = base * base #square the number
base = list(str(base)) #convert the number into a list of strings
rbase = base[:] #make a copy of the number
rbase.reverse() #reverse this copy
if len(base) > 1:
i = 0
flag = 1
while i < len(base) and flag == 1:
if base[i] == rbase[i]: #compare the values at the indices
flag = 1
else:
flag = 0
i += 1
if flag == 1:
print(''.join(base)) #print if values match
base = ''.join(base)
base = int(base)
base = count + 1
count = count + 1
palindrome(limit)
He're my version:
import sys
def palindrome(limit):
for i in range(limit):
istring = str(i*i)
if istring == istring[::-1]:
print(istring,end=" ")
print()
palindrome(int(sys.argv[1]))
Timings for your version on my machine:
pu#pumbair: ~/Projects/Stackexchange time python3 palin1.py 100000
121 484 676 10201 12321 14641 40804 44944 69696 94249 698896 1002001 1234321
4008004 5221225 6948496 100020001 102030201 104060401 121242121 123454321 125686521
400080004 404090404 522808225 617323716 942060249
real 0m0.457s
user 0m0.437s
sys 0m0.012s
and for mine:
pu#pumbair: ~/Projects/Stackexchange time python3 palin2.py 100000
0 1 4 9
121 484 676 10201 12321 14641 40804 44944 69696 94249 698896 1002001 1234321
4008004 5221225 6948496 100020001 102030201 104060401 121242121 123454321 125686521
400080004 404090404 522808225 617323716 942060249
real 0m0.122s
user 0m0.104s
sys 0m0.010s
BTW, my version gives more results (0, 1, 4, 9).
Surely something like this will perform better (avoiding the unnecessary extra list operations) and is more readable:
def palindrome(limit):
base = 1
while base < limit:
squared = str(base * base)
reversed = squared[::-1]
if squared == reversed:
print(squared)
base += 1
limit = int(input("Enter a number: "))
palindrome(limit)
I think we can do it a little bit easier.
def palindrome(limit):
count = 1
while count < limit:
base = count * count # square the number
base = str(base) # convert the number into a string
rbase = base[::-1] # make a reverse of the string
if base == rbase:
print(base) #print if values match
count += 1
limit = int(input("Enter a number: "))
palindrome(limit)
String into number and number into string conversions were unnecessary. Strings can be compared, this is why you shouldn't make a loop.
You can keep a list of square palindromes upto a certain limit(say L) in memory.If the Input number x is less than sqrt(L) ,you can simply iterate over the list of palindromes and print them.This way you wont have to iterate over every number and check if its square is palindrome .
You can find a list of square palindromes here : http://www.fengyuan.com/palindrome.html
OK, here's my program. It caches valid suffixes for squares (i.e. the values of n^2 mod 10^k for a fixed k), and then searches for squares which have both that suffix and start with the suffix reversed. This program is very fast: in 24 seconds, it lists all the palindromic squares up to 10^24.
from collections import defaultdict
# algorithm will print palindromic squares x**2 up to x = 10**n.
# efficiency is O(max(10**k, n*10**(n-k)))
n = 16
k = 6
cache = defaultdict(list)
print 0, 0 # special case
# Calculate everything up to 10**k; these will be the prefix/suffix pairs we use later
tail = 10**k
for i in xrange(tail):
if i % 10 == 0: # can't end with 0 and still be a palindrome
continue
sq = i*i
s = str(sq)
if s == s[::-1]:
print i, s
prefix = int(str(sq % tail).zfill(k)[::-1])
cache[prefix].append(i)
prefixes = sorted(cache)
# Loop through the rest, but only consider matching prefix/suffix pairs
for l in xrange(k*2+1, n*2+1):
for p in prefixes:
low = (p * 10**(l-k))**.5
high = ((p+1) * 10**(l-k))**.5
low = int(low / tail) * tail
high = (int(high / tail) + 1) * tail
for n in xrange(low, high, tail):
for suf in cache[p]:
x = n + suf
s = str(x*x)
if s == s[::-1]:
print x, s
Sample output:
0 0
1 1
2 4
3 9
11 121
22 484
26 676
101 10201
111 12321
121 14641
202 40804
212 44944
<snip>
111010010111 12323222344844322232321
111100001111 12343210246864201234321
111283619361 12384043938083934048321
112247658961 12599536942224963599521
128817084669 16593841302620314839561
200000000002 40000000000800000000004

leading number groups between two numbers

(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.

Categories

Resources