LeetCode 2193: Minimum Number of Moves to Make Palindrome

link

Similarly to how we validate if a string is a palindrome, we turn the string into a palindrome starting with the two ends and converging towards the center. If the two ends do not match, we change one end into another, taking the cheaper of the two available options.

Time: \mathcal{O}(n^2), space: \mathcal{O}(n).

class Solution:
    def move(self, s: List[str], begin: int, nsteps: int, step: int) -> None:
        while nsteps > 0:
            next = begin+step
            s[begin], s[next] = s[next], s[begin] 
            begin = next
            nsteps -= 1

    def find_first(self, target: str, s: List[str], begin: int, step: int) -> int:
        while s[begin] != target:
            begin += step
        
        return begin

    def minMovesToMakePalindrome(self, s: str) -> int:
        char_list = list(s)

        move_count = 0
        left, right = 0, len(char_list)-1
        while left < right:
            p, q = char_list[left], char_list[right]
            
            if p == q:
                left += 1
                right -= 1
                continue
            
            # pair looks like (p, q)
            # How costly to turn p into q
            q_index = self.find_first(q, char_list, left+1, 1)
            q_distance = q_index - left
            # How costly to turn q into p
            p_index = self.find_first(p, char_list, right-1, -1)
            p_distance = right - p_index

            if q_distance <= p_distance:
                move_count += q_distance
                # p......q_index......q
                self.move(char_list, q_index, q_distance, -1)
            else:
                move_count += p_distance
                # p......p_index......q
                self.move(char_list, p_index, p_distance, 1)
            
            left += 1
            right -= 1

        return move_count

Leave a comment