雙周賽73。一直想不到怎麼處理奇數字元,比賽結束後馬上看到別人的正確方法,自己修改後成功AC,也算是睡前的安慰吧。

題目

字串s,每次可以將任意兩個相鄰的字元交換位置,求最少需要幾次交換可以將s變成回文字串。

解法

很直覺知道回文一定要用到雙指標,左右邊往內夾,若碰到字元不同就開始交換。
先決定移動左半邊的字串,來和右半邊達到平衡。
當s[left]!=s[right]時,指標ll為預訂和left交換的位置,將ll不斷右移直到s[ll]與s[right]相同後停止。若ll小於right則代表該字元確實有剩餘兩個以上,將ll左移至left後,左右指標內縮一步,繼續處理下一批字元;但如果該字元只剩下一個,理當是要擺正中間去,比賽時我一直想著要先把他移到中間去,試著不少次都沒成功。後來看到這篇文才知道原來只需要把那個奇數字元先往中間靠一步,左右指標不變,再次處理即可,如此一來該奇數字元最後依然會跑到中間去。

class Solution:
    def minMovesToMakePalindrome(self, s: str) -> int:
        N = len(s)
        s = list(s)

        def shift(left, ll):
            while left < ll:
                s[ll-1], s[ll] = s[ll], s[ll-1]
                ll -= 1

        step = 0
        left = 0
        right = N-1

        while left < right:
            ll = 0
            if s[left] != s[right]:
                ll = left+1
                while s[ll] != s[right]:
                    ll += 1
                if ll == right:
                    step += 1
                    shift(right-1, right)
                else:
                    step += ll-left
                    shift(left, ll)
            else:
                left += 1
                right -= 1

        return step

2022-3-8更新list版解法。

class Solution:
    def minMovesToMakePalindrome(self, s: str) -> int:
        li = list(s)
        step = 0
        while len(li) > 1:
            if li[0] == li[-1]:
                li = li[1:-1]
            else:
                idx = 1
                t = 1
                while li[idx] != li[-1]:
                    idx += 1
                    t += 1
                if idx == len(li)-1:
                    li[-1], li[-2] = li[-2], li[-1]
                    step += 1
                else:
                    step += t
                    li = li[:idx]+li[idx+1:-1]

        return step

2022-6-17更新。一樣用list,但是看起來乾淨多了。

class Solution:
    def minMovesToMakePalindrome(self, s: str) -> int:
        s=list(s)
        ans=0
        l=0
        r=len(s)-1
        while l<r:
            rr=r
            while s[rr]!=s[l]:
                rr-=1
            if rr==l:
                ans+=1
                s[l],s[l+1]=s[l+1],s[l]
                continue
            ans+=r-rr
            t=s.pop(rr)
            s.append(t)
            l+=1
            r-=1
                
        return ans