1

Not sure what to do here, anyone know what's up? I'm trying to find if a number is a palindrome, and I'm getting hung up with the input -121. The output should be 'false', as in it is not a palindrome, whereas 121 is.

LeetCode code:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        x = str(x)
        xrev = x[::-1]
        if x == xrev:
            return 'true'
        else:
            return 'false'

This returns 'true', 'false' is expected. Whereas my code ran on Atom returns 'false' as expected:

def isPalindrome(x):
    x = str(x)
    xrev = x[::-1]
    if x == xrev:
        return 'true'
    else:
        return 'false'

print(isPalindrome(-121))
khelwood
  • 55,782
  • 14
  • 81
  • 108
Sam
  • 11
  • 2
  • 1
    Welcome to SO! Why are you returning strings that happen to have the words `"true"` and `"false"` in them instead of boolean values `True` and `False`? LC is probably treating `"false"` as truthy. Try running this code in your repl: `bool("false")`. It's best to avoid bare booleans anyway, you can just `return str(x) == str(x)[::-1]`. – ggorlen Aug 26 '21 at 22:39
  • 4
    Since your method has type hint `-> bool` it definitely should not be returning strings. – khelwood Aug 26 '21 at 22:43
  • There is no case where a negative number is a palindrome, so you should really start with `if x < 0` check, or read the conditions of your LeetCode site that probably say the input is always `x > 0` – OneCricketeer Aug 26 '21 at 22:45
  • 2
    @OneCricketeer Why make it more complicated? – no comment Aug 26 '21 at 22:50
  • @don'ttalkjustcode The "correct" (i.e. optimal) way to do this is to **not** use a string and instead modulo and divide by 10's to get the individual integers to compare – OneCricketeer Aug 27 '21 at 00:01
  • @OneCricketeer In what way is that "optimal"? Sounds like more code and slower. – no comment Aug 27 '21 at 00:08
  • @don'ttalkjustcode It doesn't require creating two string objects. It still runs in linear time. More code doesn't mean anything is slower – OneCricketeer Aug 27 '21 at 00:35
  • @don'ttalkjustcode it's definitely more code, and the shorter code is both easier to write and verify for correctness. But I think the speed will be a wash, integer to string conversion has to follow roughly the same process as digit extraction. – Mark Ransom Aug 27 '21 at 00:44
  • @OneCricketeer Well it requires creating int objects instead. Linear time sounds wrong, either you consider the input numbers limited and then it's constant time, or you don't and then it's probably quadratic time. I didn't mean it's slower *because* it's more code. – no comment Aug 27 '21 at 00:44
  • @OneCricketeer What do you do with the "individual integers"? Modulo 10 only gives you the *last* digit, how do you compare it with the *first* digit? Do you store them all in a list and compare at the end, or how do you do it? – no comment Aug 27 '21 at 01:05
  • @MarkRansom [Small benchmark](https://tio.run/##fZDdTsMwDIXv@xS@64/Ktmywn0jlirdACHVrSg2tUyWeJjTt2UvStEiARG6S40/HPk7/yY2mzb43w1Ab3QFjp5ABu14bnlQ0ElNS5a6JnBqNJ2UDqtQJu7Kd2VOQUVSpGvqyRVaWXy2bhFIZgTsWCgh6lEbx2ZCvuvKzlHfi5ZcZib/NlwZbBRSEPwTLZQFiNRaiWhtQgOQDv6lErHIQ@8lKbu4asgzUKNFJ3zmOF@8aKZmWSmKx3tw/bHf7Q5zDR0FpGnKyzx3@JGnL7liV8ud@mOZA5@6oTCEmC/5j8bP/Wnrj63XsGkq4@rebm4FQ21Tu8urmgxPPCGd0CKh49BTQwpVxyVYuRH0bE1iwrb4oE6fD8AU) where just dividing by 10 until 0 is already 15 times slower than the whole string solution. – no comment Aug 27 '21 at 01:18
  • @don'ttalkjustcode interesting benchmark. I suppose `str` is faster because it's done in C instead of pure Python, and it's a Knuth algorithm which you would expect to be more optimized than the naive division. – Mark Ransom Aug 27 '21 at 02:41
  • @MarkRansom [New benchmark](https://tio.run/##fVDLTsMwELznK/aWhwKtW2jTSLnxFwhFaeyQhWQd2S4IIb492HUSUIvYiz07O/uY4cO0krbZoMaxUbIHg71AA9gPUpkJBWdGVcTtMzF1K7EW2lNc1NhX3cw9eBgEXDQwVB0aoU2pjYowzgOwoaEAj89QCXNS5LI2/ZjnN@zpQoxkFvF7i50A9MAFwmpVAFt7DZXaDu9Kjm@oUZKOaBI2UkEJSO6UZ7GkXdDSwhWJnyK2ToFlUyXZtTeQJCACP7cAt1gY3r5IpGjyJArZZnt3v9tnhzCF14Li2J9p3Nne0qir@iOv8kt7UqBTfxSqYJME/5F4U64k/FrylyeXukG5fk1oF8nh0/3tvgkwsYvzfcq/3MFkZgpn6uAp21nPHP/NhfE4fgM): `n_small_divisions` does as many divisions (but of smaller numbers) as `palitest_int` but is much faster. So it's not the Python, it's the division work in C. – no comment Aug 27 '21 at 03:08
  • @MarkRansom And actually we could also tell that just by looking at the times. They grow quadratically (doubling the number of digits quadrupled the time). The Python code interpretation is only linear (twice as many digits => twice as many divisions), and thus not responsible for that quadratic growth. – no comment Aug 27 '21 at 03:20
  • @don'ttalkjustcode yes, working with really large integers is really slow in Python - that's not a surprise. Your benchmark is using some outrageously large integers. I once took advantage of that slowness to create a function that's faster than `str` when used with integers above about 100,000 digits: https://stackoverflow.com/a/53644080/5987 – Mark Ransom Aug 27 '21 at 03:56
  • @MarkRansom Very elegant. I'm not surprised that mul/div on two large numbers leads to something faster. I was hoping for a similar speedup for `str` on large numbers. [Back here](https://tio.run/##fVBdS8QwEHzvr9i3fnBag@idgfrkvxCRXpvahSYpyR6HlP72mm1aQUH3ZTMzzO5sxk/qrbk/jW5ZOmc1EGqFBKhH62hDyaq42rShbUrTW2yUj1KrGtT1sGsvESZJqzoY6wFJeXr35DKTywRCeagg4hU6RRdnmA30q5Q34u2XGQ19m689DgpMBFwGyrICcbcSSWddYNBw4A@ViQOI0@bEsJYnpccUCtiWm4s@Kwc8oCgeVoo4X7w9G2p9bmv58w7MD5uvii2OIvzHx4v/8I2OxS4NoyVM/A4JChDqMZfHQztzdEO7hLv0FKXqmVVADxNhSV7eim5eY3jwg72G4/hPJqzmNF@WLw), divisions-by-10 seems faster than the str ... – no comment Aug 27 '21 at 04:47
  • @MarkRansom ... solution for numbers with <= 6 digits, but then again that's still just the divisions, as I don't know how OneCricketeer intends to do the comparing. – no comment Aug 27 '21 at 04:49
  • @don't See here how you get the digits https://stackoverflow.com/questions/50660606/check-if-a-number-is-a-palindrome-without-changing-it-into-string – OneCricketeer Aug 27 '21 at 13:21
  • @OneCricketeer [Benchmark](https://pastebin.com/raw/PDDBNbWH) - That first solution is slower for any number size, up to 40 times slower. That second solution is a bit faster for numbers < 100 but then becomes up to 25 times slower. Do you still consider them optimal? – no comment Aug 27 '21 at 15:39

2 Answers2

2

As @khelwood in the comments pointed out, since the LeetCode code is hinted to return a boolean, the string value is automatically converted to a boolean value, which only if the string is empty, will return False.

Corrected code:

class Solution:
    def isPalindrome(self, x: int) -> bool:
        x = str(x)
        xrev = x[::-1]
        if x == xrev:
            return True
        else:
            return False
LuckElixir
  • 306
  • 3
  • 14
  • 1
    This worked, thanks! I thought I should have used 'true' and 'false' because of the requested outputs by LC. – Sam Aug 26 '21 at 22:57
  • @Sam this can be simplified even further. When you see `if condition: return True else: return False` you can always replace it with `return condition`. Or worst case, `return bool(condition)`. – Mark Ransom Aug 26 '21 at 23:59
0

try this, instead of true and false return 1 and 0:

class Solution:
    def isPalindrome(self, x) -> bool:
        x = str(x)
        xrev = x[::-1]
        if x == xrev:
            return 1
        else:
            return 0
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
Zeeshan Arif
  • 467
  • 4
  • 14
  • 2
    Did you know that True==1 and False==0 by definition? While your code might work, it's better to be explicit. – Mark Ransom Aug 26 '21 at 23:57