What's wrong with my code?Valid Palindrome 2- Leetcode 680

Question:

Given a string s, return true if the s can be palindrome after deleting at most one character from it.

Example 1:

Input: s = "aba"
Output: true

Example 2:

Input: s = "abca"
Output: true
Explanation: You could delete the character 'c'.

Example 3:

Input: s = "abc"
Output: false

For this problem in leetcode my code has passed 462/469 test cases:

Following is the test case for which my code is failing the test.

"aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga"

My code is:

class Solution:
    def validPalindrome(self, s: str) -> bool:
        
        skip=0
        l,r=0,len(s)-1
        
        while l<r:
            if s[l]==s[r]:
                l+=1
                r-=1
            elif s[l]!=s[r] and skip<1 and s[l+1]==s[r]:
                l+=1
                skip=1
            elif s[l]!=s[r] and skip<1 and s[r-1]==s[l]:
                r-=1
                skip=1
            else:
                return False
        return True

What is the problem with my code?

Note: in this string the output should be true, mine returns false

From left there are characters ‘lcup’ and from right there are characters ‘lucup’
My code is supposed to skip the letter u from right side and continue.

"aguokepatgbnvfqmgm**lcup**uufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuu**pucul**mgmqfvnbgtapekouga"

Another example: It returns true for the following string:
s='adau'

Skips letter ‘u’ as expected.

However when I use the example according to the test case string that failed, it returns False. s= 'cuppucu'

It should skip first u from the right side and return True but it doesn’t.

However as soon as I replace that last letter ‘u’ with letter ‘a’ it skips the letter ‘a’ and returns True. What’s the problem here?

Asked By: redox741

||

Answers:

Imagine the string 'abbab'. First you check index 0 and 4 with the values "a" and "b". They are not the same, but the "b" at index 1 matches the "b" at index 4. So you move forward to 1 and 4. Next is 2 and 3 and those are "b" and "a" and those don’t match too. End of the story.

abbab
l   r

abbab
 l  r

abbab
  lr

-> False

Now let’s switch around the elif blocks. Again you check index 0 and 4 first. They are not the same, so you now change the right index first and see that 0 and 3 are both "a". The next comparison is at indexes 1 and 2 with "b". Finished. Found a match.

abbab
l   r

abbab
l  r

abbab
 lr

-> True

You didn’t ask for it but here is a working solution with a different approach.

class Solution:
    def generate_strings(self, s):
        yield s, s[::-1]
        for pos in range(len(s)):
            t = ''.join(c for i, c in enumerate(s) if i != pos)
            yield t, t[::-1]

    def validPalindrome(self, p):
        return any(x == y for x, y in self.generate_strings(p))
Answered By: Matthias

I over-complicated this in my first answer. I thought that you had to skip a particular character multiple times. As others have pointed out, that isn’t true. So you have a solution from someone else, but you wanted to know how to change your code to always do the right thing. One way would be to run your algorithm twice. The first time, you only consider if you can skip a character on the left side of the input string as you’re walking over it. For the second call, you only consider skipping a character on the right side. For cases like the one you ran into here where you could choose to skip either character, but only one will produce a positive result, well then if you try both cases, one or the other will always succeed when it should.

So here’s that simple change you can make…modifying your function only slightly, and then calling it twice.

class Solution:

    def _validPalindrome(self, s: str, choose_first: bool) -> bool:
        skip = 0
        l, r = 0, len(s) - 1
        while l < r:
            if s[l] == s[r]:
                l += 1
                r -= 1
            elif choose_first and s[l] != s[r] and skip < 1 and s[r - 1] == s[l]:
                r -= 1
                skip = 1
            elif not choose_first and s[l] != s[r] and skip < 1 and s[l + 1] == s[r]:
                l += 1
                skip = 1
            else:
                return False
        return True

    def validPalindrome(self, s: str) -> bool:
        return self._validPalindrome(s, False) or self._validPalindrome(s, True)

def main():
    inp = "aguokepatgbnvfqmgmlcupuufxoohdfpgjdmysgvhmvffcnqxjjxqncffvmhvgsymdjgpfdhooxfuupuculmgmqfvnbgtapekouga"
    print(Solution().validPalindrome(inp))

main()

Result:

True

This should pass for all the cases for which your original code passed.

Answered By: CryptoFool
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.