patternpythonMinor
Finding the next palindrome code
Viewed 0 times
thenextpalindromefindingcode
Problem
I have been trying recently to develop a code finding the next palindrome from a certain number. For example, if the input is 800, the output should be 808, as 808 being the next palindrome from 800.
Here's my code. It's fully functional, but on my online judge I get a problem with the time of the execution. My method is not optimal. Any advice on this?
Here's my code. It's fully functional, but on my online judge I get a problem with the time of the execution. My method is not optimal. Any advice on this?
def reverseNumber(a):
degreMax = findDegree(a)
result = 0
while a != 0:
r = a % 10
a = a // 10
result = result + r*10**degreMax
degreMax = degreMax - 1
return result
def findDegree(a):
degre = 0
while a >= 10:
a = a/10
degre = degre + 1
return degre
def isPalindrome(a):
test = False
if reverseNumber(a) == a:
test = True
return test
def nextPalindrome(a):
while isPalindrome(a) == False:
a = a + 1
return a
nbTest = int(raw_input())
inputs = []
for i in range(0,nbTest):
a = int(raw_input())
inputs.append(a)
for i in range(0,len(inputs)):
print nextPalindrome(inputs[i])Solution
A bit of style
Before anything, let's rewrite/reorganise the code a bit to make it more pythonic but also easier to test.
Python has a style guide called PEP8. Among other things, you do not follow the naming and spacing conventions. You might find interesting to know that there are various tools to check your code (against PEP8 but also for various other things : pep8, pylint, pychecker, pyflakes and even tools to fix style automatically like autopep8.
Also, it is usual (and very useful) to use an
So far, your "improved" code looks like :
So far, I haven't done anything relevant as far as performances are concerned and you might think I'm wasting your time here. I'm almost done.
More style
So far, I've done cosmetic changes. A few other changes can be performed to make your code more beautiful but also potentially faster (even if it is very subtle).
-
Python has a
-
You don't need a temporary variable in
-
You don't need to provide first argument to
-
You don't need temporary variable
-
In Python 2 (which is the version I am guessing you are using),
-
It is the convention to name
-
Whenever you are using
It's easy/concise/hard to get wrong/fast.
-
to create a list and fill it, instead of having a boring loop and
-
you can use division assignment
-
you don't even need to store inputs into an array, you can just compute and print answers as you do over inputs.
At this stage, your code looks like :
User interface
A last note before diving into performances. It might be convenient to tell the user what you are asking him. Otherwise, one might think your program is just computing stuff when it is just waiting for input.
Mesuring performances
In order to improve performance, it is best to be able to measure it while ensuring correctness. This can be achieved through unit tests. Without being bothered with a full unit testing framework, you can just write things like :
```
def unit_tests():
assert next_palindrome(5) == 5
assert next_palindrome(10) == 11
assert next_palindrome(80) == 88
assert next_palindrome(12345678) == 12355321
assert next_palin
Before anything, let's rewrite/reorganise the code a bit to make it more pythonic but also easier to test.
Python has a style guide called PEP8. Among other things, you do not follow the naming and spacing conventions. You might find interesting to know that there are various tools to check your code (against PEP8 but also for various other things : pep8, pylint, pychecker, pyflakes and even tools to fix style automatically like autopep8.
Also, it is usual (and very useful) to use an
if __name__ == '__main__': guard so that you have your definitions (classes, functions, constants, etc) on one hand and your actual program doing something on the other hand.So far, your "improved" code looks like :
def reverse_number(a):
degreMax = find_degree(a)
result = 0
while a != 0:
r = a % 10
a = a // 10
result = result + r*10**degreMax
degreMax = degreMax - 1
return result
def find_degree(a):
degre = 0
while a >= 10:
a = a/10
degre = degre + 1
return degre
def is_palindrome(a):
test = False
if reverse_number(a) == a:
test = True
return test
def next_palindrome(a):
while not is_palindrome(a):
a = a + 1
return a
if __name__ == '__main__':
nb_test = int(raw_input())
inputs = []
for i in range(0, nb_test):
a = int(raw_input())
inputs.append(a)
# inputs = [5, 10, 303, 800]
for i in range(0, len(inputs)):
print next_palindrome(inputs[i])So far, I haven't done anything relevant as far as performances are concerned and you might think I'm wasting your time here. I'm almost done.
More style
So far, I've done cosmetic changes. A few other changes can be performed to make your code more beautiful but also potentially faster (even if it is very subtle).
-
Python has a
divmod function which does exactly what you are trying to do in reverse_number.-
You don't need a temporary variable in
is_palindrome.-
You don't need to provide first argument to
range if you start at 0 and step is 1.-
You don't need temporary variable
a in your main.-
In Python 2 (which is the version I am guessing you are using),
range creates a list which might be more than what you want. If you just need something to iterate on, xrange is what you need (in most cases this is what you need and it's why it is the behavior for range in Python 3).-
It is the convention to name
_ a variable whose variable is not used such as i in your code initialising the input list.-
Whenever you are using
range and len to iterate over a container, you are most probably doing something wrong. Python provides you a way to iterate over something that can hardly be easier : for i in inputs:
print next_palindrome(i)It's easy/concise/hard to get wrong/fast.
-
to create a list and fill it, instead of having a boring loop and
append, Python has a very expressive way to do it : list comprehension. If you have never read about them, make yourself a favor and just google it. In your case, defining your inputs gets down to this :inputs = [int(raw_input()) for _ in xrange(nb_test)]-
you can use division assignment
/= to write a /= 10 instead of a = a/10. Also (and this is more common), you can use += and -= in various places of your code.-
you don't even need to store inputs into an array, you can just compute and print answers as you do over inputs.
At this stage, your code looks like :
def reverse_number(a):
degreMax = find_degree(a)
result = 0
while a != 0:
a, r = divmod(a, 10)
result = result + r*10**degreMax
degreMax -= 1
return result
def find_degree(a):
degre = 0
while a >= 10:
a /= 10
degre += 1
return degre
def is_palindrome(a):
return reverse_number(a) == a
def next_palindrome(a):
while not is_palindrome(a):
a += 1
return a
if __name__ == '__main__':
nb_test = int(raw_input())
inputs = [int(raw_input()) for _ in xrange(nb_test)]
# inputs = [5, 10, 303, 800]
for i in inputs:
print next_palindrome(i)User interface
A last note before diving into performances. It might be convenient to tell the user what you are asking him. Otherwise, one might think your program is just computing stuff when it is just waiting for input.
nb_test = int(raw_input("Nb tests? "))
inputs = [int(raw_input("Test ? ")) for _ in xrange(nb_test)]Mesuring performances
In order to improve performance, it is best to be able to measure it while ensuring correctness. This can be achieved through unit tests. Without being bothered with a full unit testing framework, you can just write things like :
```
def unit_tests():
assert next_palindrome(5) == 5
assert next_palindrome(10) == 11
assert next_palindrome(80) == 88
assert next_palindrome(12345678) == 12355321
assert next_palin
Code Snippets
def reverse_number(a):
degreMax = find_degree(a)
result = 0
while a != 0:
r = a % 10
a = a // 10
result = result + r*10**degreMax
degreMax = degreMax - 1
return result
def find_degree(a):
degre = 0
while a >= 10:
a = a/10
degre = degre + 1
return degre
def is_palindrome(a):
test = False
if reverse_number(a) == a:
test = True
return test
def next_palindrome(a):
while not is_palindrome(a):
a = a + 1
return a
if __name__ == '__main__':
nb_test = int(raw_input())
inputs = []
for i in range(0, nb_test):
a = int(raw_input())
inputs.append(a)
# inputs = [5, 10, 303, 800]
for i in range(0, len(inputs)):
print next_palindrome(inputs[i])for i in inputs:
print next_palindrome(i)inputs = [int(raw_input()) for _ in xrange(nb_test)]def reverse_number(a):
degreMax = find_degree(a)
result = 0
while a != 0:
a, r = divmod(a, 10)
result = result + r*10**degreMax
degreMax -= 1
return result
def find_degree(a):
degre = 0
while a >= 10:
a /= 10
degre += 1
return degre
def is_palindrome(a):
return reverse_number(a) == a
def next_palindrome(a):
while not is_palindrome(a):
a += 1
return a
if __name__ == '__main__':
nb_test = int(raw_input())
inputs = [int(raw_input()) for _ in xrange(nb_test)]
# inputs = [5, 10, 303, 800]
for i in inputs:
print next_palindrome(i)nb_test = int(raw_input("Nb tests? "))
inputs = [int(raw_input("Test ? ")) for _ in xrange(nb_test)]Context
StackExchange Code Review Q#81962, answer score: 6
Revisions (0)
No revisions yet.