周賽308。題目超臭長的模擬題,花了超久才搞懂在問什麼,而且還很簡單。

題目

輸入字串陣列garbage,其中garbage[i]表示第i個房子的垃圾。garbage[i]由字元”M”,”P”和”G”組成,分別代表一個金屬、紙或玻璃垃圾。回收一單位的垃圾皆須要1分鐘。
還有一個整數陣列travel,其中travel[i]是從第i個房子到第i+1個房子所需的分鐘數。

共有三輛垃圾車,每輛負責收一種垃圾。每輛垃圾車從0號房開始,按順序訪問各個房屋;但是不需要訪問所有房屋。
同一個時間點只有一台垃圾車可以動作:當某台正在移動或是收垃圾時,另外兩台必須待機。

求回收所有垃圾最少需要幾分鐘。

解法

不需要訪問所有房屋指的是:若後方的房屋沒有出現某種垃圾,則對應的垃圾車不必繼續往後開。所以我們要維護三個變數,分別記錄三台垃圾車應該開到哪個位置。
至於回收的垃圾,反正每一種都是要花費1分鐘,所以收垃圾的總時間其實就是所有字串的加總長度。
最後是垃圾車的行車時間,因為垃圾車數量只有三台,沒有什麼太大的影響,可以直接暴力求和。

遍歷所有垃圾的時間複雜度為O(N*10*3),可以當作O(N)。而計算移動距離是O(N*3),一樣當作O(N)。整體複雜度O(N)。

class Solution:
    def garbageCollection(self, garbage: List[str], travel: List[int]) -> int:
        time=0
        mcar=pcar=gcar=0
        
        for i,s in enumerate(garbage):
            time+=len(s)
            if 'M' in s:
                mcar=i
            if 'P' in s:
                pcar=i
            if 'G' in s:
                gcar=i
        
        for i,n in enumerate(travel):
            i=i+1
            for car in [mcar,pcar,gcar]:
                if car>=i:
                    time+=n

        return time

如果垃圾車有很多台,上面求行車距離的部份會變成O(N*M),很有可能超時。
可以先對房屋的距離做前綴和,以O(1)的成本得到每台車的移動距離,將整題複雜度保持在O(N)。
紀錄垃圾車位置也要稍微修改一下,換成雜湊表,確保每個垃圾堆只需要遍歷一次。

class Solution:
    def garbageCollection(self, garbage: List[str], travel: List[int]) -> int:
        time=0
        cars={}
        psum=[0]*(len(travel)+1)
        for i,n in enumerate(travel):
            psum[i+1]=psum[i]+n
            
        for i,s in enumerate(garbage):
            time+=len(s)
            for car in s:
                cars[car]=i
            
        for i in cars.values():
            time+=psum[i]
        
        return time