Why does 101010 return `True` when the expression`str(000) in str(101010)` is evaluated in Python?

117 views Asked by At

I'm working on this LeetCode problem here, and I'm implementing a brute force approach as well as an iterative approach. The iterative approach works fine, but my brute force approach seems to have hit an edge case. I want to determine whether a string has 3 consecutive numbers and return the highest 3 consecutive numbers in it. My code is as follows:

class Solution:
    def largestGoodInteger(self, num: str) -> str:
        if str(999) in num:
            return "999"
        elif str(888) in num:
            return "888"
        elif str(777) in num:
            return "777"
        elif str(666) in num:
            return "666"
        elif str(555) in num:
            return "555"
        elif str(444) in num:
            return "444"
        elif str(333) in num:
            return "333"
        elif str(222) in num:
            return "222"
        elif str(111) in num:
            return "111"
        elif str(000) in num:
            return "000"
        else:
            return ""

For some reason, the string 101010 returns "000" even though 000 is not sequential in the string. I figured that the in operator may be evaluating the string 000 as an array and iterating over each element in the string, but the operator does not appear to do that according to the docs. As such, why does 000 get returned instead of ""?

3

There are 3 answers

2
AndreasKralj On BEST ANSWER

It turns out that the issue didn't have anything to do with the in operator, but rather how Python evaluates string conversion. No matter how many zeroes you pass to str(), it returns a single zero as a string. Therefore, str(000) returned "0" and since the single 0 exists in the string, the statement returned True. Changing it to "000" in str(num) fixed the issue.

3
enzo On

To avoid repeating each number and keeping the same logic of your code, you can do it in a single for loop:

def largest_good_integer(self, num: str) -> str:
    for n in reversed(range(10)):
        token: str = f'{n}' * 3    # Repeat the digit thrice
        if token in num:
            return token

    return ''

or using a single function call, on Python >= 3.8:

def largest_good_integer(num: str) -> str:
    return next((token for n in reversed(range(10)) if (token := f'{n}' * 3) in num), '')

The above solution also helps to avoid falling into that str(000) trap.

2
VoNWooDSoN On

Another note on using "000" as a literal is that leading zero's are often interpreted as being in octal. Here's some fun errors from my interpreter:

>>> 001
  File "<stdin>", line 1
    001
      ^
SyntaxError: leading zeros in decimal integer literals are not permitted; use an 0o prefix for octal integers
>>> 000
0
>>>

You can see that python no longer accepts the 001 and asks for you to use 0o1 as the octal literal. Also, worth noting is that 000 results in the Integer object of 0. So then it stands to reason that str(int("000")) == '0' and in fact does. When converting strings to numbers and numbers to strings, it's important to know what these constraints are.

General advice for writing software is to assume that what you write in the code is not what's going to be executed. Rather, what you write in code is going to be interpreted by the language/compiler to something that is (hopefully) equivalent.