Skip to content

Instantly share code, notes, and snippets.

@adnauseum
Created October 31, 2018 21:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adnauseum/7dc8dcba5b45086be48f674d75fe3419 to your computer and use it in GitHub Desktop.
Save adnauseum/7dc8dcba5b45086be48f674d75fe3419 to your computer and use it in GitHub Desktop.
Integer Palindrome
class Solution:
def isPalindrome(self, user_supplied_integer):
"""
In order to avoid string conversion, the algorithm hinges on some math tricks. But it
prevents the inevitable O(n) of int-to-string conversion. Instead we can do what we
need to in O(n/2), though this is often expressed as O(n), it is still better!
Let's say your function is given the following int argument: 35753
First,
You can obtain the length of the user_supplied_integer with:
num_digits = math.floor(math.log10(x)) + 1
The length of the digit is important for knowing how long you should loop for. With the
above argument, num_digits will be 5.0.
Second,
You can use a "mask" to obtain the number in the front:
msd_mask = 10**(num_digits - 1)
first_digit = user_supplied_integer // msd_mask
In our above input, the `msd_mask` will be: 10000.0 which represents the highest decimal
place value on the left on the decimal (35753.0, for instance). Now you can see how we get
the first digit: `35753 // 10000.0` will yield `3.0`. Recall that `/` will give us 3.5753.
Third,
You can use `% 10` to obtain the number in the back:
last_digit = user_supplied_integer % 10
Basically, you are asking, what is the largest multiple of 35753 and 10? Well 10 * 3575 is
35750. 35753 - 35750 is 3. That's the last digit. Doing % 10 will always give us the last digit.
To get a better understanding of modulus division, check out: https://youtu.be/akfFEj7oTn0
You now have all that you need. With each iteration we can simulate having a "front pointer"
and a "back pointer" to check equality. Because we check two at a time, we don't have to run
once for each digit. We can run once for every two digits, hence:
`for i in range(num_digits // 2)`
Check if the front is equal to the digit in the back. If they are not, return false. If they
are the same, you'll actually be removing the front digit and the back digit.
After each iteration you'll need to remove the first and last digit from the
user_supplied_integer so that you can keep comparing numbers. You can do this by:
1) Remove the most significant digit by modulo-ing off the number in the highest tens place
user_supplied_integer %= msd_mask
Recall, what is the largest multiple of 35753 and our msd_mask, 10000? 10000 * 3 is 30000
which gives us a remainder of 5753. This is equivalent to removing the first digit in the
user_supplied_integer.
Removing the least significant digit by removing the number in the tens place by dividing
the integer by ten
user_supplied_integer //= 10
Finally, you have to shorten your msd_mask to reflect the integer you just clipped
(on both ends).
msd_mask //= 100
The `100` has two zeros--that is the number of zeroes you'll remove from your msd_mask.
If your msd_mask was 10000, it'll now become 100--that is, with the final two zeroes removed.
Repeat!
:type user_supplied_integer: int
:rtype: bool
"""
if user_supplied_integer < 0:
return False
if user_supplied_integer < 2:
return True
num_digits = math.floor(math.log10(user_supplied_integer)) + 1
msd_mask = 10**(num_digits - 1)
for i in range(num_digits // 2):
first_digit = user_supplied_integer // msd_mask
last_digit = user_supplied_integer % 10
if first_digit != last_digit:
# We don't have a palindrome
return False
# Remove the most significant digit (front)
user_supplied_integer %= msd_mask
# Remove the least significant digit (back)
user_supplied_integer //= 10
# Shorten the msd_mask to match the current user_supplied_integer
msd_mask //= 100
return True
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment