雙周賽92。這題和我的相性不太好,長度N的陣列對應到N+1種選擇,花了一點時間才想通。
再加上字元的”N”和我用來計算輸入常數的N衝突,想變數名稱卡好久,最後選了小寫n, y來計算字元”N”, “Y”感覺很不舒服。

題目

輸入由Y和N組成的字串customers,代表商店的來客紀錄:

  • 如果customers[i]為Y,則代表第i小時有客人
  • 反之,若為N,則代表第i小時沒客人

商店可以在第0<=j<=n小時之中選擇任一時間點打烊,並計算懲罰值

  • 對於每個小時,如果商店營業中,但卻沒來客,懲罰+1
  • 對於每個小時,如果商店已打烊,但卻有來客,懲罰+1

求商店可以得到最小懲罰值,且最早打烊的時間點j。

注意:在第j小時打烊,代表從包含j之後的所有時間都是關門狀態。

解法

對於每個時間j來說,若關門,懲罰為j之前的N總數+j之後(含)的Y總數,所以要先計算懲罰值後才對NY做增減。
因為剩餘的Y和已知的N都呈現單調增減,所以可以用前綴和來維護其數量。若當前時間j的懲罰值低於最低值,則更新答案。

處理完customers陣列後,記得還要處理第N小時,也就是完全不關門,懲罰值=已知N總數的情況。

總共需要遍歷陣列兩次,時間O(N),空間O(1)。

class Solution:
    def bestClosingTime(self, customers: str) -> int:
        N=len(customers)
        y=customers.count("Y")
        n=0
        mn=inf
        ans=None

        for i,c in enumerate(customers):
            penal=n+y
            if penal<mn:
                mn=penal
                ans=i
            if c=="Y":
                y-=1
            else:
                n+=1
            
        if n<mn:
            mn=n
            ans=N
            
        return ans