Palindrome numberr - python

I was making research on writing a code to check for Palindrome number in Python and I came across this
class Solution:
def isPalindrome(self, x: int) -> bool:
rev = 0
init_n = x
if (x < 0):
return False
while x != 0:
rev = (rev * 10) + x % 10
x = x // 10
if (rev == init_n):
return True
Question: Please can someone explain the while x!=0: loop for me

While I agree your question could use some extra clarification, or you don't quite understand the code you posted. Here's an explanation. Say we start x = 123
The code:
while x != 0:
rev = (rev*10) + x % 10
x = x // 10
rev = reverse and x is our start number and the edited versions we create as we go.
Each iteration does the following
The first line takes our previous rev and opens up the ones digit before adding the ones digit from the end of x's list. This is done via the mod operator in python which returns the remainder of a number. When applied with the number 10 what is left is the ones digit. Next, we remove our ones digit of x by using floor division which is division that ignores any remainder.
Using the case of x=123, the first iteration sets rev = 3 and x = 12, the second iteration sets rev = 32 and x = 1, the third rev = 321 and x = 0. Which breaks the loop. This is important as it returns the exact reverse of x, which is then compared to x in the last if statement.

Related

calculating the last non-zero digit of a factorial- why does my code pass some tests but fail others?

I am writing code to solve the following codewars question: https://www.codewars.com/kata/5f79b90c5acfd3003364a337/train/python
My idea is to take all the integers from 1 to n, and take the last digit of each of these integers (bar 0), multiply them together, and return the 'last' non-zero digit of the result:
def last_digit(n):
factorials = []
factorials_n = 1
for i in range(1,n + 1):
i = str(i)
i = i[::-1]
for j in i:
if j == "0":
break
factorials.append(j)
break
# at this point factorials contains the first non-zero integers of each integer in reverse
for i in factorials:
factorials_n = factorials_n * int(i)
factorials_n = str(factorials_n)
factorials_n = factorials_n[::-1]
for i in factorials_n:
if i != "0":
return int(i)
The code passes a number of tests, but fails for 387 (returns 6, should be 2) and 1673 (returns 2 should be 4). I've tried doing print statements as debug but the code seems fine, perhaps it's the logic that fails at some point- any ideas?
The problem here is with the logic. Since you are dropping all the cases where the number ends in 0, we do not arrive at the correct answer.
Consider 2 x 8 x 30. To get the last digit of the factorial, multiplying last digits would suffice, but to find the last non zero digit, you have to evaluate 2 x 8 x 3
instead.
Using this solution as a reference, here's what you can do:
def last_digit(n):
# factorials = []
# factorials_n = 1
last = 1
d2 = 0
for i in range(1,n + 1):
ii = i
print(ii)
while(ii%2==0):
d2 +=1
ii = ii/2
while(ii%5==0):
d2 -=1
ii = ii/5
print(d2)
last = (last * ii)%10
print(last)
for i in range(0,d2):
last = (last *2)%10
return int(last)
Your code passes the test cases for numbers uptill 24, it fails when the non-zero digit from 25! gives an incorrect answer which get propogated forward for the numbers after it.
And also we can simply use the modulo operator to get the very last digit instead of converting it into a string
Example: 1234 % 10 equals 4 (which is the last digit)
My solution:
def last_digit(n):
factorial = 1
for i in range(1, n + 1):
# compute the factorial
prod = factorial * i
# keep dividing the product by 10 until the last digit is a !0 digit
while prod % 10 == 0:
prod = prod // 10
# only store the last 3 digits of the computed product.
# You can keep more digits to get accurate results for
# when the numbers are higher than 10000
factorial = prod % 1000
# return the last digit
return factorial % 10
As i said earlier, when the last !0 digit from 24! (6) is multiplied with 25, it outputs 150 which after removing the 0 gives 5 but it instead should be 4. Hence, in order to solve this we keep at least the last 3 digits instead of only the last digit.
Example: 6 * 25 = 150 => 5 (last !0 digit)
936 * 25 = 23400 => 4 (last !0 digit)
PS: !0 = non-zero

Check if a number can be formed by sum of a number and its reverse

I want to check if a given number can be formed by another number say b and reverse(b). For example 12 == 6+6, 22 == 11 + 11 and 121 == 29+92. One thing I have figured out is if the number is multiple of 11 or it is an even number less than 20, then it can be formed. I tried to implement this below:
num = 121
if num%11==0:
print('Yes')
else:
if num%2==0 and num<20:
print('Yes')
else:
for j in range(11,(int(num)//2)+1):
if j+int(str(j)[::-1])==num:
print('Yes')
break
However, if the condition goes into the for loop, it gives TLE. Can any other conditions be given?
Update: If the reversed number has trailing zeroes, it should be removed and then added. For example: 101 == 100+1. I am looking for an optimized form of my code. Or I think I am missing some conditions which can take O(1) time, similar to the condition if num%11==0: print('Yes')
All the previous answers are not really a check. It's more a brute force try and error.
So let's do it a little bit smarter.
We start with a number, for example 246808642. we can reduce the problem to the outer 2 place values at the end and start of the number. Let us call this values A and B at the front and Y and Z on the back. the rest, in the middle, is Π. So our number looks now ABΠYZ with A = 2, B = 4, Π = 68086, Y = 4 and Z = 2. (one possible pair of numbers to sum up for this is 123404321). Is A equal to 1, this is only possible for a sum greater 10 (An assumption, but i guess it works, some proof would be nice!).
so if it is a one, we know that the second last number is one greater by the carry over. So we ignore A for the moment and compare B to Z, because they should be the same because both are the result of the addition of the same two numbers. if so, we take the remaining part Π and reduce Y by one (the carry over from the outer addition), and can start again at the top of this chart with Π(Y-1). Only a carry over can make B one bigger than Z, if it's so, we can replace B by one and start with 1Π(Y-1) at the top. B-1!=Z and B!=Z, we can stop, this isnt possible for such a number which is the sum of a number and its reversed.
If A != 1, we do everything similiar as before but now we use A instead of B. (I cut this here. The answer is long enough.)
The code:
import time
def timing(f):
def wrap(*args, **kwargs):
time1 = time.time()
ret = f(*args, **kwargs)
time2 = time.time()
print('{:s} function took {:.3f} ms'.format(f.__name__, (time2-time1)*1000.0))
return ret
return wrap
#timing
def check(num):
num = str(num)
if (int(num) < 20 and int(num)%2 == 0) or (len(num) ==2 and int(num)%11 == 0):
return print('yes')
if len(num) <= 2 and int(num)%2 != 0:
return print('no')
# get the important place values of the number x
A = num[0]
B = num[1]
remaining = num[2:-2]
Y = num[-2]
Z = num[-1]
# check if A = 1
if A == '1':
# A = 1
# check if B == Z
if B == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
# reduce the last digit about one and check again.
check(remaining + (str(int(Y)-1) if Y != '0' else '9'))
elif int(B)-1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + remaining + (str(int(Y)-1) if Y != '0' else '9'))
else:
print("Not able to formed by a sum of a number and its reversed.")
else:
# A != 1
# check if A == Z
if A == Z:
# so the outest addition matches perfectly and no carry over from inner place values is involved
check(B + remaining + Y)
elif int(A) - 1 == int(Z):
# so the outest addition matches needs a carry over from inner place values to match, so we add to
# to the remaining part of the number a leading one
# we modify the last digit of the remaining place values, because the outest had a carry over
check('1' + B + remaining + Y)
else:
print("Not able to formed by a sum of a number and its reversed.")
#timing
def loop_check(x):
for i in range(x + 1):
if i == int(str(x - i)[::-1]) and not str(x - i).endswith("0"):
print('yes, by brute force')
break
loop_check(246808642)
check(246808642)
Result:
yes, by brute force
loop_check function took 29209.069 ms
Yes
check function took 0.000 ms
And another time we see the power of math. Hope this work for you!
You can brute force it like this:
def reverse_digits(n):
return int(str(n)[::-1])
def sum_of_reversed_numbers(num):
for i in range(num + 1):
if i == reverse_digits(num - i):
return i, num - i
return None
print("Yes" if sum_of_reversed_numbers(num) else "No")
Can you provide the constraints of the problem?
Here is something you can try:
i = 0
j = num
poss = 0
while(i<=j):
if(str(i)==str(j)[::-1]):
poss = 1
break
i+=1
j-=1
if(poss):
print("Yes")
else:
print("No")
You can do it without str slicing:
def reverse(n):
r = 0
while n != 0:
r = r*10 + int(n%10)
n = int(n/10)
return r
def f(n):
for i in range(n + 1):
if i + reverse(i) == n:
return True
return False
print('Yes' if f(101) else 'No')
#Yes
The basic idea of my solution is that you first generate a mapping of digits to the digits that could make them up, so 0 can be made by either 0+0 or 1+9, 2+8 etc. (but in that case there's a carried 1 you have to keep in mind on the next step). Then you start at the smallest digit, and use that code to check each possible way to form the first digit (this gives you candidates for the first and last digit of the number that sums with its reverse to give you the input number). Then you move on the second digit and try those. This code could be greatly improved by checking both the last and the first digit together, but it's complicated by the carried 1.
import math
candidates = {}
for a in range(10):
for b in range(10):
# a, b, carry
candidates.setdefault((a + b) % 10, []).append((a, b, (a + b) // 10))
def sum_of_reversed_numbers(num):
# We reverse the digits because Arabic numerals come from Arabic, which is
# written right-to-left, whereas English text and arrays are written left-to-right
digits = [int(d) for d in str(num)[::-1]]
# result, carry, digit_index
test_cases = [([None] * len(digits), 0, 0)]
if len(digits) > 1 and str(num).startswith("1"):
test_cases.append(([None] * (len(digits) - 1), 0, 0))
results = []
while test_cases:
result, carry, digit_index = test_cases.pop(0)
if None in result:
# % 10 because if the current digit is a 0 but we have a carry from
# the previous digit, it means that the result and its reverse need
# to actually sum to 9 here so that the +1 carry turns it into a 0
cur_digit = (digits[digit_index] - carry) % 10
for a, b, new_carry in candidates[cur_digit]:
new_result = result[::]
new_result[digit_index] = a
new_result[-(digit_index + 1)] = b
test_cases.append((new_result, new_carry, digit_index + 1))
else:
if result[-1] == 0 and num != 0: # forbid 050 + 050 == 100
continue
i = "".join(str(x) for x in result)
i, j = int(i), int(i[::-1])
if i + j == num:
results.append((min(i, j), max(i, j)))
return results if results else None
We can check the above code by pre-calculating the sums of all numbers from 0 to 10ⁿ and their reverse and storing them in a dict of lists called correct (a list because there's many ways to form the same number, eg. 11+11 == 02 + 20), which means we have the correct answers for 10ⁿ⁻¹ we can use to check the above function. Btw, if you're doing this a lot with small numbers, this pre-calculating approach is faster at the expense of memory.
If this code prints nothing it means it works (or your terminal is broken :) )
correct = {}
for num in range(1000000):
backwards = int(str(num)[::-1])
components = min(num, backwards), max(num, backwards)
summed = num + backwards
correct.setdefault(summed, []).append(components)
for i in range(100000):
try:
test = sum_of_reversed_numbers(i)
except Exception as e:
raise Exception(i) from e
if test is None:
if i in correct:
print(i, test, correct.get(i))
elif sorted(test) != sorted(correct[i]):
print(i, test, correct.get(i))
Stole the idea from #Doluk. I was asked this question in a test today. I couldn't solve it then. With Doluk's idea and thinking seriously on it below is a decision tree kind for one level of recursion. I might be wrong as I haven't ran this algorithm.
Let n be the number, we want to check if special
case 1: leading number is not 1
case 1a: no carry over from inner addition
abcdefgh
hgfedcba
x x => (a+h) < 10
if both ends are same in n, strip both sides by one digit and recurse
case 1b: carry over from inner addition
1
abcdefgh
hgfedcba
(x+1)......(x) => (a+h+1) < 10
if left end is 1 greater than right end in n, strip both sides by one digit, add digit 1 on the left and recurse
case 2: leading number is 1
case 2a: no carry over from inner addition
1 1
abcdefgh
hgfedcba
1x x => (a+h) >= 10
strip - if second and last digit are same, strip two digits from left and one from right, from the remaining number minus 1 and recurse.
case 2b: carry over from inner addition
case 2bi: a+h = 9
11
abcdefgh
hgfedcba
10......9
strip - two from left and one from right and recurse.
case 2bj: a+h >= 10
11 1
abcdefgh
hgfedcba
1(x+1)......x
strip - two from left and one from right and subtract 1 from number and recurse.
In my question, they gave me an array of numbers and they asked me to find numbers which of them are special (Which can be formed by the sum and reverse of that number).
My brute force solution was to iterate from 0 to 1000000 and insert them into the set and last check for each element in the set.
Time Complexity: O(n)
Space Complexity: O(n)
where n is the highest number allowed.

Reversing an integer using recursion in Python

While practicing recursion I came across a question to reverse an integer using recursion. I tried to do the question without converting the integer into a string.
I was able to solve the question partially but the output would always come without any of the zeroes from the original input. Below is the code I came up with:
def reverseNumber(n):
if (n//10) == 0:
return n
lastDigit = n%10
ans = reverseNumber(n//10)
nod = 0
for i in str(ans):
nod += 1
return (10**nod)*lastDigit + ans
Upon inspection I could see that this was happening because when lastDigit is 0 it only returned the reversed integer from the recursive call i.e input 4230 will give 324.
But this also meant that all zeroes between the original input would also get removed as we went deeper in the recursive calls.
So please tell me how to modify this code so that zeroes in the original input are not removed while reversing.
You probably need just this:
def rev(n):
if n>0:
return str(n%10)+rev(n//10)
else:
return ''
reverseNumber should return an int and accept positive and negative numbers.
The simplest way to fix your code, without handling negative numbers, is:
def reverseNumber(n):
if n == 0:
return 0
lastDigit = n%10
n //= 10
return int(str(lastDigit) + str(reverseNumber(n))) if n else lastDigit
for test in (0, 123, 120):
print(test, reverseNumber(test))
Prints:
0 0
123 321
120 21
Yes! The reverse of 120 is 21 when you are dealing with int types as opposed to str types.
Another implementation that does handle negative numbers takes a whole different approach:
I have broken this out into two functions. Function rev is a generator function that assumes that it is being called with a positive, non-negative number and will recursively yield successive digits of the number in reverse. reverseNumber will join these numbers, convert to an int, adjust the sign and return the final result.
def reverseNumber(n):
def rev(n):
assert n >= 0
yield str(n % 10)
n //= 10
if n != 0:
yield from rev(n)
if n == 0: return 0 # special case
x = int(''.join(rev(abs(n))))
return x if n >= 0 else -x
tests = [0, 132, -132, 120]
for test in tests:
print(test, reverseNumber(test))
Prints:
0 0
132 231
-132 -231
120 21
For all non-negative n, when n < 10 it is a single digit and already the same as its reverse -
def reverse(n = 0):
if n < 10:
return str(n)
else
return str(n%10) + rev(n//10)
you can also try the following Python3 code. It will cover positive and negative integers to be reversed as integers - not as strings ...
x = int(input("What integer shall be reversed? "))
n = abs(x) # ... to handle negative integers
r = 0 # ... will hold the reversed int.
while n > 0: # Recursion part reversing int.
r = (r * 10) + (n % 10) # using '%' modulo
n = int(n / 10) # and a 'dirty way' to floor
if x < 0: # Turn result neg. if x was neg.
return (r * -1)
else:
return r # Keep result pos. if x was pos.
This approach will leave your zeros in the middle of the integer intact, though it will make any zero at the end of the initial number vanish - rightfully so as integers do not start with a zero. ;))

finds the upper and lower Fibonacci boundaries of a given number

I found the a code in a website and I do not quite understand how it works or finds the upper and lower Fibonacci boundaries of a given number.
I want to understand how the code runs with an example like with x = 6
def fib_intervall(x):
""" returns the largest fibonacci
number smaller than x and the lowest
fibonacci number higher than x"""
if x < 0:
return -1
(old,new, lub) = (0,1,0)
while True:
if new < x:
lub = new
(old,new) = (new,old+new)
else:
return (lub, new)
while True:
x = int(input("Your number: "))
if x <= 0:
break
(lub, sup) = fib_intervall(x)
print("Largest Fibonacci Number smaller than x: " + str(lub))
print("Smallest Fibonacci Number larger than x: " + str(sup)
First of all you must examine each line of code and try to change some lines if you really want to understand.
For answer:
Step 1. You will go in to infinite while loop and 6 will be assigned to x.
Step 2. X<=0 is false, therefor fib_intervall(6) will be called, and then result will be assigned to lub,sub.
Step 3. inside fib_intervall:
{1 - if statement is false(6>0.
2 - old = 0 new = 1 lub = 0 assignments will be done.
3 - The other infinite loop will be executed:
new was 1 and 1<6 so if statement will be executed. old(0) will be new(1) and new will be old + new
[ old = 0 new = old + new.]
loop will continue as following
[ old = 1 new = 2]->[ old = 2 new = 3]->[ old = 3 new = 5]->[ old = 5 new = 8]
after last assignments new = 8 > 6 so else statement will be executed and function will return (5,8) and these are the fibonacci boundaries of 6.}
Step 4. 5 will be printed with lub variable. 8 will be printed with sup variable :
Largest Fibonacci Number smaller than x: 5
Smallest Fibonacci Number larger than x: 8

While loop creating

I am writing a program in Python that defines a function that takes a single argument. The function has to be a while loop the returns the largest power of 16 that it is equal to. However, I am not sure how to write the while loop.
Python Docs
while True:
n = input("Please enter 'hello':")
if n.strip() == 'hello':
break
so, in layman's terms
while <condition>:
...
I couldn't completely understand your question but here's how to do a while loop to get the x to the 16th power of an input:
def loop_function(x):
y = 1
start = x
while y != 16:
result = start * x
start = result
y += 1
return result
print loop_function(3)
The above code will return the answer to 3^16 which is 43046721
You can even make this a broader function two arguements
def loop_function(x, y):
z = 1
start = x
while z != z:
result = start * x
start = result
z += 1
return result
print loop_function(3, 2)
The above code will return 9 i.e 3^2

Categories

Resources