-1

I have found a recursive solution to check whether a linked list is a palindrome:

def isPalindrome(self, head: ListNode) -> bool:

    self.front_pointer = head

    def recursively_check(head):
        if head:
            if not recursively_check(head.next):
                return False
            if self.front_pointer.val != head.val:
                return False
            self.front_pointer = self.front_pointer.next
        return True

    return recursively_check(head)

After the 'if head' statement:

Why are we returning False for the first if statement, when "recursively_check(head.next)" points to None? This would be okay, no? Because it simply means we've reached the end of the linked list, or am I reading this wrongly?

For the second if statement, this kind of makes sense- in my mind it is checking the first node front_pointer and the last node head are the same?

Then we are simply moving the front_pointer, which initially points to the head of the linked list to the next node to check? But while I understand this, from the back end, how are we moving from the last node to the second last node?

Finally, why do we return the recursive call recursively_check()? I don't see when we will reach this code- as we would have returned True or False by the time we reach here, no?

hefu fhiwh
  • 105
  • 5
  • 2
    Have you tested this code, or are you only assuming that it works? – khelwood Jun 11 '21 at 07:14
  • I have tested it and it works now- the only thing missing was the argument 'head' in the last 'recursive check. – hefu fhiwh Jun 11 '21 at 07:40
  • I suggest you debug it: check the values of `head` and `self.front_pointer` in each call to `recursively_check`. The trick is a bit subtle. Consider what the effect is of having `head` be a function parameter and `front_pointer` be an attribute of the containing object. And try and restrict yourself to one specific question per post. – khelwood Jun 11 '21 at 08:07

1 Answers1

1

After the if head statement: Why are we returning False for the first if statement, when recursively_check(head.next) points to None? This would be okay, no? Because it simply means we've reached the end of the linked list, or am I reading this wrongly?

recursively_check(head.next) does not "point to None". It is a boolean: either it is True, either it is False. Interpret a True as "so far it looks like a palindrome" and interpret a False as "this definitely is not a palindrome".

This particular return False is intended to get out of recursion with a failure that was detected deeper in the recursion call tree. Here we just pass on that message to the caller, who will do the same. It is not related to having reached the end of the list. It is triggered by a difference found deeper in the recursion tree.

For the second if statement, this kind of makes sense- in my mind it is checking the first node front_pointer and the last node head are the same?

Yes, the first time it gets executed, it is like that.

Then we are simply moving the front_pointer, which initially points to the head of the linked list to the next node to check?

Yes

But while I understand this, from the back end, how are we moving from the last node to the second last node?

This is taken care of by recursion. Each recursive call gets to get its own head variable. And as we initialise it with head.next, the deeper recursive calls will have their head initialised further in the list.

That means that when we backtrack out of a level of recursion, we get into an execution context that has its head variable set to a previous node than the one that the deeper call was using (as we gave it head.next). So by merely returning out of the current execution context, we fall back to a previous value of head, which corresponds to taking a step back in the list. But do realise that we have as many head variables here as there are nodes in the list. They all get stacked on top of each other in the recursion call stack. By unwinding the call stack we get to work with the previous head variable.

Finally, why do we return the recursive call recursively_check()? I don't see when we will reach this code- as we would have returned True or False by the time we reach here, no?

We reach this statement immediately. The function above it, is not yet executed when we arrive there. It is this statement that will start the recursion, and we need to get information from that call, and that information is what we want to return.

This is the only return statement for isPalindrome. The other return statements serve recursively_check only. They don't execute a return for isPalindrome.

Every time we exit a nested execution of recursively_check we have tested one more pair of nodes. If ever we find a difference in value, we start returning False. Like explained above, this False will from then on be the return value for all unfinished calls of recursively_check, including the one that is made directly in isPalindrome.

On the other hand, as long as the comparisons are equal, a True will be returned by each nested recursively_check call. If it turns out the comparisons were always equal, then also isPalindrome's call to recursively_check will get a True back.

trincot
  • 317,000
  • 35
  • 244
  • 286