Checking if an integer is a palindrome using either a string or a dict I have solved the palindrome question on LeetCode today, but I wasn't happy with the original solution - I used strings, it worked slowly and used a lot of memory.
So I rewrote the answer using a dictionary approach instead knowing that looking up a value in a dictionary has lower time complexity than searching through a list, but the results were strange - my latest answer is much better in terms of memory use (better than 94.65% of other submissions), but it became significantly slower. As you can see in the image below, my last submission is much slower than the first, but memory use has improved a lot:

My original solution was this:
class Solution:
    def isPalindrome(self, x: int) -&gt; bool:        
        s = str(x)
        
        if len(s) == 1:
            palindrome = True
            
        i = int(len(s)/2)
        
        for p in range(i):
            if s[p] != s[-(p+1)]:
                return False
            else:
                palindrome = True
        
        return palindrome 

And the updated version is:
class Solution:
    def isPalindrome(self, x: int) -&gt; bool:        
        s = {i:j for i,j in enumerate(str(x))} 
        i = (max(s)+1)//2
    
        if max(s)+1 == 1:
            return True
        
        for p in range(i):
            if s[p] != s[max(s)-p]:
                return False
            else:
                palindrome = True
        
        return palindrome

Can anyone explain why the latest version is so much slower? I thought it should be faster...
What should I change to improve the speed?
EDIT:
New version based on @hjpotter comment. Now I only have 1 call to max() in the entire script and yet it's even worse - 168ms and 13.9 Mb. I don't understand what's happening here:
class Solution:
    def isPalindrome(self, x: int) -&gt; bool:
        s = {i:j for i,j in enumerate(str(x))} 
        m = max(s)
        i = (m+1)//2
    
        if m+1 == 1:
            return True
        
        for p in range(i):
            if s[p] != s[m-p]:
                return False
            else:
                palindrome = True
        
        return palindrome
Apart from performance, there are several other problems in your implementation which the other answers did not address.

This should not be a class. It should be a function, because it being a class offers no advantage whatsoever and it makes its usage more complex.
The variable palindrome is unnecessary and confuses the reader: this variable is always going to be True. So remove it.
Don’t cast the result of a division to int. Use integer division instead.
The if len(s) == 1 check is redundant: its logic is already subsumed in the subsequent code.
Use descriptive variable names: s for an arbitrary string is fine but i to denote the middle index of a sequence is cryptic.

An improved implementation (without changing the algorithm) would look as follows:
def is_palindrome(n: int) -&gt; bool:
    s = str(n)
    mid = len(s) // 2
    for i in range(mid):
        if s[i] != s[-i - 1]:
             return False
    return True

Or, using a generator expression:
def is_palindrome(n: int) -&gt; bool:
    s = str(n)
    mid = len(s) // 2
    return all(s[i] == s[-i - 1] for i in range(mid))

… and of course this whole loop could also be replaced with return s[:mid] == s[: -mid - 1 : -1] because Python gives us powerful subsetting.

I also want to address a misconception in your question:

looking up a value in a dictionary has lower time complexity than searching through a list,

That’s only true if the dictionary has the same size as the sequence (more or less …), and if looking up the key is constant. Neither is true in your case. But what’s more, you still need to construct the list/dictionary, and you completely omit the complexity of these operations.
In fact, the first thing your dictionary does is also construct the sequence — namely, by invoking str(x). It then goes on to traverse the whole list! Because that’s what i:j for i,j in enumerate(str(x)) does.
So before even starting your algorithm proper, it has already performed more work than your other implementation which, after all, only needs to traverse half the string. Even if you stopped at this point and returned, the second implementation would already be slower than the first, and you haven’t even finished constructing the dictionary yet (constructing the dictionary from key: value mappings also takes time).
As for the actual algorithm, you’re still traversing half the string, so once again you are doing the same work as your initial algorithm. This means you have the same asymptotic complexity. But even that part of the second algorithm is slower, because a dictionary is a much more complex data structure than a plain sequence, and each key access of the dictionary (s[p]) is substantially slower than the same access on a string or list would be.