在古早時代,如果製作遊戲時要使用動畫,有時候一張一張的圖片讀取進來,電腦的效能無法支撐.所以在比較爛的電腦上就會一卡一卡的不滑順.這個時候就會改為使用滑動視窗動畫來呈現.
這個作法是這樣的,把所有動畫都放在一張大圖上面,但是用一個小視窗當成呈現的區塊.而其他區塊就不呈現在使用者面前.當要更新動畫內容的時候,不用重新載入圖片,而是只要移動小視窗,這樣就會自行更新呈現的樣子,完成動畫效果.
(比如說上面這張圖要展示爆炸的動畫,只要用穩定的速度從(2,2)格移動到(2,5)格,看起來就有那麼一回事)
而滑動視窗演算法也像是這樣,我們維護一個不停移動的視窗,然後更新答案
這個演算法的思考大概如下
fun windowAlgo(s:Array<T>){
var left = 0
var right = 0
while(right<s.size){
//增大視窗
window.add(s[right])
right++
while ( window needs shrink){//檢查需要縮小視窗
//縮小視窗
window.remove(s[left])
left++
}
}
}
這種演算法的時間複雜度是O(N),比字串暴力演算有效的多.
其實困難的不是演算法的思路,而是細節很多.例如如何讓視窗增加元素,如何縮小視窗,在滑動的哪個階段更新結果.即使明白這些細節,也很容易有bug,而且bug還很難找.
所以我們將思考擴寫成框架
fun slidingWindow(s: String, t: String) {
val need: HashMap<Char, Int> = HashMap()
val window: HashMap<Char, Int> = HashMap()
t.forEach { need[it] = 1 }
var left = 0
var right = 0
var valid = 0
while(right<s.length){
//c是即將移入視窗的字元
val c = s[right]
//右移視窗
right++
//進行視窗內的一系列更新
...
while(whindow need shrink){
//d 是即將移出視窗的字元
val d = s[left]
//左移視窗
left++
//進行視窗內的一系列更新
...
}
}
}
其中...代表要更新資料的地方,根據題目填入邏輯即可.而且這兩處的操作,會分別是右邊進入以及左邊移除的操作,而之後會發現這兩者完全相同.