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
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.
I am trying to implement Luhn algorithm in Python. Here is my code
def validate(n):
if len(str(n)) > 16:
return False
else:
if len(str(n)) % 2 == 0:
for i in str(n[0::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
elif len(str(n)) % 2 != 0:
for i in str(n[1::2]):
digit = int(str(n[i])) * 2
while digit > 9:
digit = sum(map(int, str(digit)))
dig_sum = sum(map(int, str(n)))
return True if dig_sum % 10 == 0 else False
I keep getting the error
TypeError: 'int' object has no attribute '__getitem__
Following is python implementation of Lunh Algorith to detect a valid credit card number. Function takes a number as string and return whether its valid credit card or not.
Its based on the steps mentioned in the following link: https://www.codeproject.com/Tips/515367/Validate-credit-card-number-with-Mod-algorithm
Step 1 - Starting with the check digit double the value of every other digit (right to left every 2nd digit)
Step 2 - If doubling of a number results in a two digits number, add up the digits to get a single digit number. This will results in eight single digit numbers.
Step 3 - Now add the un-doubled digits to the odd places
Step 4 - Add up all the digits in this number
If the final sum is divisible by 10, then the credit card number is valid. If it is not divisible by 10, the number is invalid.
def luhn(ccn):
c = [int(x) for x in ccn[::-2]]
u2 = [(2*int(y))//10+(2*int(y))%10 for y in ccn[-2::-2]]
return sum(c+u2)%10 == 0
#Test
print(luhn("49927398716"))
It is hard to tell without the complete error message, but it is likely because you confused in some places where you put the indexing and where you put the string conversion, for example: for i in str(**n[1::2]**) and digit = int(str(**n[i]**)) * 2
A good way to handle it is to just create a temporary variable n_str = str(n), and use it instead of str(n) over and over again.
Okay, i have made my code so that a user can input 7 numbers and times them by 1 for the odd index numbers and 3 for the even:
num = str(input("Please enter 7 numbers")
length = len(num)
while length < 7 or length ? 7:
num = input("Only enter 7 numbers")
string = ''
for t in range(1,8):
if t % 2 == 0:
string += str(t * 3)
else:
string += str(t) + ' '
print(string)
This works fine, but now i need to add all the numbers up and take it away from the highest 10 so for example, all the numbers add up to 53 i need to take that away from 60 which leaves me 7, that will be my eight number, then after i have got that number i print it out, how do i get it to add the numbers up and the take it away from the highest 10 and output the difference of the two into the numbers i already have?
Thanks
Brad
If you have a number, x, which is equal to 53, then going up should be math.ceil(x) except that math.ceil() rounds for 1. To account for that, we divide by 10, use math.ceil(), and then multiply by 10 again:
import math
rounded_up = math.ceil(x / 10) * 10
result = rounded_up - x
Brad could you clarify your question? Also your above code does not work.
Missing a bracket on the first line and this isn't valid while length < 7 or length ? 7:
I believe this is what you're looking for:
def take_away_from_nearest(number, nearest):
return nearest - (number % nearest)
Usage:
>>> take_away_from_nearest(53, 10)
7
edit:
If I understand you correctly, this would be the entire code:
while True:
# this is just an easy way to keep asking until the input is correct
num = input("Please enter 7 numbers: ")
if len(num) == 7:
break
weird_sum = 0 #here's where we're gonna sum up the numbers; the "eighth number"
for index, character in enumerate(num):
if index % 2 == 0: # index is odd, so count the character thrice
print(3 * int(character))
weird_sum += 3 * int(character)
else: # index is even
print(int(character))
weird_sum += int(character)
print(10 - (weird_sum % 10)) # 10 minus (weird_sum modulo 10)
# and finally, adding them all up and checking whether it ends with 0:
print((10-(weird_sum % 10) + weird_sum) % 10 == 0) # prints True
I am currently trying to use the luhn method to determine whether a credit card is valid or not in python and here is what I have so far:
print('What is your Credit Card number? :) (please put a space between each number)')
a = [int(x) for x in input().split()]
lengthy = len(a)
print(lengthy)
a.reverse()
print(a)
listx2 = []
listx1 = []
for x in range(len(a)):
modulus = x % 2
print(x, a[x])
if modulus != 0:
listx2.append(a[x]*2)
else:
listx1.append(a[x])
print(listx2)
print(listx1)
I don't know how to do the next step which is getting the sum of all of the digits of the numbers multiplied by two.(listx2) I have looked at different programs with the luhn method but I just can't seem to pick that part out. Thanks!
This is my interpretation of the Luhn algo.
def luhn(sequence):
digits = [int(digit) for digit in str(sequence)] # converts a full string of nums to a list comp of individual numbers
odd = digits[-1::-2] # string stepping (-1) indicates last item in list (-2) means to travel back another 2
even = digits[-2::-2]
checksum = 0
checksum += sum(odd)
evenmod = []
for digit in even:
if digit * 2 > 9:
digit = digit * 2
digit = int(str(digit)[0]) + int(str(digit)[1])
else:digit = digit * 2
evenmod.append(digit)
checksum += sum(evenmod)
if checksum % 10 == 0:
return True
else:
return False
print luhn(378282246310005)
print luhn(111111111111111)
print luhn(4751290083628479)
print luhn(5573485043994670)
Separate the even and the odd indeces to separate lists, then use a for statement to loop through the list, multiplying the list entries by two.
Notice the if statement that catches the issue with (e.g) 8 * 2 = 16.
Use sum:
summed_x2 = sum(listx2)