python upside-down number puzzle. Need assistance with efficiency - python

An upside-down number is defined as:
An upside-down number is an integer where the i'th digit from the left plus the i'th digit from the right is
always equal to 10.
For example 13579 is an upside-down number since 1+9 = 10, 3+7 = 10 and (since
5 is both the 3rd digit from the left and from the right) 5+5 = 10.
The first few upside-down numbers, in numerical order, are 5, 19, 28, 37, … , 82, 91, 159, …
Task: Write a program to determine the nth upside-down number (in numerical order).
The input will consist of a single integer n (1 < n < 2^31). You should output a single integer giving the nth upside-down number.
My code:
def upsidecheck(tocheck):
intolist=list(map(int, str(tocheck)))
x=0
while x<(len(intolist)/2):
if (intolist[x]+intolist[len(intolist)-x-1])!= 10 :
return False
break
x+=1
return True
print("which nth upsidedownnumber do you want?")
nth=int(input())
y=0
answer=0
for x in range (1,(2**31)):
counter=upsidecheck(x)
if counter == True:y+=1
if y==nth:answer=x;break
print("the answeris",answer)
Performance issue:
This code is fine for numbers less than 100, however it needs to run within two seconds for numbers as large as '1234' which should yield an answer of '4995116'.
It does work but just takes too long (usually about 30 seconds). It needs to work within 2 seconds ;(
[Note: this is not for an exam/homework etc., it's just to help me prepare for an exam.]

First, we need a function to tell us which numbers are upside-down:
def is_ud(n):
digits = [int(ch) for ch in str(n)]
check = (len(digits) + 1) // 2
return all(digits[i] + digits[-1 - i] == 10 for i in range(check))
then let's generate some values and look for patterns:
ud = [i for i in range(10000000) if is_ud(i)]
for digits in range(1, 8):
lo, hi = 10 ** (digits - 1), (10 ** digits) - 1
answers = sum(lo <= n <= hi for n in ud)
print("{}: {}".format(digits, answers))
which gives
1: 1
2: 9
3: 9
4: 81
5: 81
6: 729
7: 729
so there are 81 4-digit solutions, and 729 6-digit solutions; this should make sense, because the 6-digit solutions look like "1" + (each 4-digit solution) + "9", "2" + (each 4-digit solution) + "8", ... "9" + (each 4-digit solution) + "1" - therefore, there are 9 6-digit solutions for every 4-digit solution (and if you generate them in this fashion you will be generating them in ascending order). Similarly, for each 4-digit solution, there is a corresponding 5-digit solution by sticking a 5 in the middle.
Looking at this table, you should now be able to see that if you want (for example) the 200th solution, it must have 6 digits; in fact, it must be the 19th 6-digit solution. More than this, because 19 < 81, it must look like "1" + the 19th 4-digit solution + "9"!
You now have everything you need to write a recursive solution to directly generate the Nth upside-down number. Good luck!

Since brute-forcing through all the numbers here is not an option, you need to first solve the mathematical problem:
Generate "upside-down" numbers in ascending order and,
If possible, determine how many "upside-down" numbers there are of a certain length since your index cap is pretty high to brute-force-generate even these.
For the 1st, "upside-down" numbers are:
of length 2n: a1...ana'n...a'1
of length 2n+1: a1...an5a'n...a'1
where ai is any digit except 0 and a'i is its 10-complement.
Since the numbers of the same length are compared digit by digit, guess which order will be the ascending one.
For the 2nd,
the number of "upside-down" numbers of length 2n or 2n+1 is both the number of all the possible combinations of a1...an.
since the previous expression is so simple, you can even work out a formula for the sum - the number of all "upside-down" numbers up to the length N.
The rest is pretty simple, i'd only add that divmod or // may come in handy for the resulting algorithm.

This is an interesting problem. The first part, as others have said, is that you want the nth number of any number of digits, so if you can find the total number of values with fewer digits you can subtract them from the value and ignore them.
Then you have a simpler problem: find the nth value with exactly k digits. If k is odd the central digit is '5', but otherwise the first half is simply the nth base 9 number but with digits expressed in the range 1..9. The tail is simply the same base 9 value with the digits reversed and using a range of 9..1 to represent values 0..8.
This function will convert a value to base 9 but with a specific character used to represent each digit:
def base9(n, size, digits):
result = []
for i in range(size):
result.append(n%9)
n //= 9
return ''.join(digits[i] for i in reversed(result))
So for example:
>>> print(base9(20, 3, "abcdefghi"))
acc
Now to print the nth upside down number with exactly k digits we convert to base 9 and insert a '5' if required.
def ud_fixed(n, k):
"""Upside down number of exactly k digits
0 => 1..159..9
1 => 1..258..9
and so on
"""
ln = k // 2
left = base9(n, ln, "123456789")
right = base9(n, ln, "987654321")[::-1]
if k%2:
return left + "5" + right
else:
return left + right
Now all we need to do is count how many shorter results there are and ignore them:
def upside_down(n):
number = [1, 9]
total = [1, 10]
if n==1: return "5"
while total[-1] < n:
number.append(9*number[-2])
total.append(total[-1]+number[-1])
length = len(total)
if length >= 2:
n -= total[length-2] # Ignore all the shorter results.
return ud_fixed(n-1, length)
Print some values to check:
if __name__=='__main__':
for i in range(1, 21):
print(i, upside_down(i))
print(1234, upside_down(1234))
Output looks like:
C:\Temp>u2d.py
1 5
2 19
3 28
4 37
5 46
6 55
7 64
8 73
9 82
10 91
11 159
12 258
13 357
14 456
15 555
16 654
17 753
18 852
19 951
20 1199
1234 4995116

Upside-down Numbers
Code is in a module, from which the OP can import the ud function.
% cat upside.py
# module variables
# a table with the values of n for which we have the greatest
# UD number of i digits
_t = [0, 1]
for i in range(1,11): last = _t[-1] ; d=9**i ; _t+=[last+d,last+d+d]
# a string with valid digits in our base 9 conversion
_d = '123456789'
def _b9(n,l):
# base 9 conversion using the numbers from 1 to 9
# note that we need a zero padding
s9 = []
while n : s9.append(_d[n%9]) ; n = n//9
while len(s9)<l: s9.append(_d[0]) # ZERO PADDING!
s9.reverse()
return ''.join(s9)
def _r9(s):
# reverse the first half of our UD number
return ''.join(str(10-int(c)) for c in s[::-1])
def ud(n):
# Error conditions
if n<1:raise ValueError, 'U-D numbers count starts from 1, current index is %d.'%(n,)
if n>_t[-1]:raise ValueError, 'n=%d is too large, current max is %d.'%(n,_t[-1])
# find length of the UD number searching in table _t
for i, j in enumerate(_t):
if n<=j: break
# the sequence number of n in all the OD numbers of length i
# note that to apply base9 conversion we have to count from 0,
# hence the final -1
dn = n-_t[i-1]-1
# now we compute the "shifted base 9" representation of the ordinal dn,
# taking into account the possible need for padding to a length of i//2
a = _b9(dn,i//2)
# we compute the string representing the OD number by using _r9 for
# the second part of the number and adding a '5' iff i is odd,
# we convert to int, done
return int(a+('5' if i%2 else '')+_r9(a))
%
Usage Example
Here it is an example of usage
% python
Python 2.7.8 (default, Oct 18 2014, 12:50:18)
[GCC 4.9.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from upside import ud
>>> ud(1234)
4995116
>>> ud(7845264901)
999999999951111111111L
>>> ud(7845264902)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "upside.py", line 15, in ud
if n>_t[-1]:raise ValueError, 'n=%d is too large, current max is %d.'%(n,_t[-1])
ValueError: n=7845264902 is too large, current max is 7845264901.
>>> exit()
%
A small remark
Except for comments and error handling, ud(n) is amazingly short...
def ud(n):
for i, j in enumerate(_t):
if n<=j: break
dn = n-_t[i-1]-1
a = _b9(dn,i//2)
return int(a+('5' if i%2 else '')+_r9(a))

Related

Calculate the sequence of continuous numbers

I'm trying to find a way to calculate the amount of continuous digits on a given number. IE Number 7 has 7 continuous digits, while number 10 has 11 continuous digits. Here's an image to depict the problem
The first row shows the sequence and the second one shows the amount of numbers this has.
This has to be on python, but any ideas will help
Here is my attempt at understanding your question.
def continuous_digits(x):
count = 0
for i in range(1,x+1):
s = str(i)
count += len(s)
return count
# Test the function
for i in range(7,12):
print(f'Number: {i}: Continuous Digit Length: {continuous_digits(i)}')
The output:
Number: 7: Continuous Digit Length: 7
Number: 8: Continuous Digit Length: 8
Number: 9: Continuous Digit Length: 9
Number: 10: Continuous Digit Length: 11
Number: 11: Continuous Digit Length: 13
You could build a string with all the digits and get its length (but that's not very efficient):
n = 103
r = len("".join(map(str,range(1,n+1)))) # 201
Alternatively what you can do it compute the number of 1-digit, 2-digit, ... x-digit values that are below n. You can figure out these numbers starting with the largest number of digit (which you can obtain using the base 10 logarithm).
from math import log
d = int(log(n,10))
r = (d+1)*(n+1-10**d) + sum((i+1)*9*10**i for i in range(d)) # 201

Formatting unknown output in a table in Python

Help! I'm a Python beginner given the assignment of displaying the Collatz Sequence from a user-inputted integer, and displaying the contents in columns and rows. As you may know, the results could be 10 numbers, 30, or 100. I'm supposed to use '\t'. I've tried many variations, but at best, only get a single column. e.g.
def sequence(number):
if number % 2 == 0:
return number // 2
else:
result = number * 3 + 1
return result
n = int(input('Enter any positive integer to see Collatz Sequence:\n'))
while sequence != 1:
n = sequence(int(n))
print('%s\t' % n)
if n == 1:
print('\nThank you! The number 1 is the end of the Collatz Sequence')
break
Which yields a single vertical column, rather than the results being displayed horizontally. Ideally, I'd like to display 10 results left to right, and then go to another line. Thanks for any ideas!
Something like this maybe:
def get_collatz(n):
return [n // 2, n * 3 + 1][n % 2]
while True:
user_input = input("Enter a positive integer: ")
try:
n = int(user_input)
assert n > 1
except (ValueError, AssertionError):
continue
else:
break
sequence = [n]
while True:
last_item = sequence[-1]
if last_item == 1:
break
sequence.append(get_collatz(last_item))
print(*sequence, sep="\t")
Output:
Enter a positive integer: 12
12 6 3 10 5 16 8 4 2 1
>>>
EDIT Trying to keep it similar to your code:
I would change your sequence function to something like this:
def get_collatz(n):
if n % 2 == 0:
return n // 2
return n * 3 + 1
I called it get_collatz because I think that is more descriptive than sequence, it's still not a great name though - if you wanted to be super explicit maybe get_collatz_at_n or something.
Notice, I took the else branch out entirely, since it's not required. If n % 2 == 0, then we return from the function, so either you return in the body of the if or you return one line below - no else necessary.
For the rest, maybe:
last_number = int(input("Enter a positive integer: "))
while last_number != 1:
print(last_number, end="\t")
last_number = get_collatz(last_number)
In Python, print has an optional keyword parameter named end, which by default is \n. It signifies which character should be printed at the very end of a print-statement. By simply changing it to \t, you can print all elements of the sequence on one line, separated by tabs (since each number in the sequence invokes a separate print-statement).
With this approach, however, you'll have to make sure to print the trailing 1 after the while loop has ended, since the loop will terminate as soon as last_number becomes 1, which means the loop won't have a chance to print it.
Another way of printing the sequence (with separating tabs), would be to store the sequence in a list, and then use str.join to create a string out of the list, where each element is separated by some string or character. Of course this requires that all elements in the list are strings to begin with - in this case I'm using map to convert the integers to strings:
result = "\t".join(map(str, [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]))
print(result)
Output:
12 6 3 10 5 16 8 4 2 1
>>>

Solving Python Riddle

Problem I am supposed to solve:
The Riddler is planning his next caper somewhere on
Pennsylvania Avenue. The address on Pennsylvania is a four-digit number with
the following properties.
All four digits are different,
The digit in the thousands place is three times the digit in the tens place,
The number is odd, and
The sum of the digits is 27.
So I made a for loop that checks each four digit integer and puts the value in a place holder (i.e. thousands, hundreds, etc.) And conditional if statements to fit the conditions. But my problem is that the IDE gives me no error when I run the code, but it does not print my statement at the end. I'm having trouble figuring out what is wrong with my code.
address = 0
thousand = 0
hundred = 0
ten = 0
one = 0
for address in range(1000,9999+1):
thousand = (address/1000)%10
hundred = (address/100)%10
ten = (address/10)%10
one = (address%10)
if (thousand != hundred) and (thousand != ten) and (thousand != one) and (hundred != ten) and (hundred != one) and (ten !=one):
if thousand == (3*ten):
if one % 2 != 0:
if thousand+hundred+ten+one == 27:
print("The address is: ",address, "Pennsylvania Ave.")
It runs but the print statement does not show up.
All four digits are different, The digit in the thousands place is three times the digit in the tens place, The number is odd, and The sum of the digits is 27.
The digit in the thousands place is three times the digit in the tens place: valid combos are 3x1x, 6x2x, 9x3x.
The sum of the digits is 27: only 9x3x is possible since 27 - (6 + 2) > 8+7, the maximum remaining digits. In fact 27 - (9 + 3) = 15. The remaining digits can be 9,6 or 8,7
All four digits are different: 9,5 is not an option. The number is either 9837 or 9738.
The number is odd: it's 9837.
Some pencil and paper works better than a for loop here.
That being said, keep in mind that / is the true division operator in Python 3, irrespective of type. So when address = 6754, for example
thousand = (address / 1000) % 10
evaluates as
thousand = 6.754 % 10
which is just 6.754, not 6 as you were probably hoping. To get 6, use the integer division operator //:
thousand = (address // 1000) % 10
Number Theory
isop = []
for a in range(1, 10, 1):
for b in range(0, 10, 1):
for c in range(0, 10, 1):
for d in range(0, 10, 1):
if a!=b and a!=c and a!=d and b!=c and b!=d and c!=d:
sum = a+b+c+d
if a==3*c and sum == 27:
num = a*1000 + b*100 + c*10 + d
if num % 2 == 1:
isop.append(num)
for i in range(len(isop)):
print(isop[i])

Python3 check digit algorithm

I'm learning to wrap my head around programming and have been given the following task:
The ISBN (International Standard Book Number) is made out of 10 digits.
z1z2z3z4z5z6z7z8z9z10
The last digit z10 is a check-digit. It's made like this: First, you create a kind of cross-sum with this formula:
s = 1 * z1 + 2 * z2 + 3 * z3 + 4 * z4 + 5 * z5 + 6 * z6 + 7 * z7 + 8 * z8 + 9 * z9
The check-digit z10 is the remainder of the integer division of s divided by 11. For the remainder 10 you write x or X. Example: For the ISBN 3826604237 you get the check-digit 7.
Calculation: 1*3+2*8+3*2+4*6+5*6+6*0+7*4+8*2+9*3 = 150
The remainder of the division of 150 and 11 is 7.
The code-solution given is as followed:
# isbn.py
number = int(input("Please enter a 9-digit number: "))
z9 = number % 10
number = number//10
z8 = number % 10
number = number//10
z7 = number % 10
number = number//10
z6 = number % 10
number = number//10
z5 = number % 10
number = number//10
z4 = number % 10
number = number//10
z3 = number % 10
number = number//10
z2 = number % 10
number = number//10
z1 = number
sum = z1+2*z2+3*z3+4*z4+5*z5+6*z6+7*z7+8*z8+9*z9
checkdigit = sum%11
print("\nCheckdigit:", checkdigit)
My question simply is: How does it work? Why do I have to calculate "number // 10" and "number % 10" and this all the time? Is there a name for this kind of algorithm, and if so, how is it called?
I'd appreciate any kind of answer for this and if it seems like the easiest thing for you and you feel like I'm wasting your time, I'm sorry. So far I understood pretty much anything I've learned thus far learning python, but this task seemed a bit hard (it was in a very early chapter of the book I'm studying on work) and I got stuck and didn't get this out of my head.
Thank you in advance and have a nice day!
The operation x % 10 is called 'modulus' and returns the remainder of the division by 10. You use it in your code to isolate the rightmost digit.
The next operation x // 10 is called 'integer division', that is, a division which returns integers only (the fractional part (if any) is cut off). Integer division by 10 on a decimal number corresponds to a rightshift by one digit so that the next digit is shifted into the rightmost place.
You repeat these 2 steps until the last digit is isolated. Then you perform the multiplications, and finally take the modulus of 11 (the remainder of the division by 11) to obtain the check digit.
This repetitive code cries for a loop. Just imagine you had to handle 100 digit numbers.
You are using % aka modulus and integer division // to get one digit a time.
It is easier to not convert the whole number into an integer and then extract the individual digits, but to process the inputted string character wise.
Throw in some input validation and you get:
while True:
# don't convert to int
# repeat until exactly 9 digits are given
number = input("Please enter a 9-digit number: ").strip()
if number.isdigit() and len(number) == 9:
break
# generator method - enumerate gives you the position and the value of each character
# i.e. for enumerate('123') you get (0,'1') then (1,'2') then (2,'3')
# the sum function adds up each given tuple but premultiplies the value with its (pos+1) as position inside strings start at 0 for the 1st character - it also
# converts each single character to its integer value
s1 = sum( (pos+1)*int(num) for pos,num in enumerate(number))
# s1 is a summed generator expression for this:
s2 = 0 # do not use sum - its a built-in functions name
for pos,num in enumerate(number):
s2 += (pos+1)*int(num)
print(s1,s2) # both are the same ;o)
checkdigit = s1%11
print("\nCheckdigit:", checkdigit)
For 382660423 you get:
150 150
Checkdigit: 7
It's began from modulo arytmetic. And module, length of ICBN and coefficients is just agreement, cause coefficients has no matter (by modulo arytmetic properties (if x mod y = 0, than k * x mod y = 0, where k is integer)).

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

Categories

Resources