氣球遊戲
1 背景
面試騰訊,面試官感覺很忙,一邊工作一邊面試,一上來自我介紹都省了,直接就是這道題,讓半小時寫出來,面試的時候思路理出來了,但是平時滑動視窗寫的少,自然是沒寫出來了,假期特地惡補了滑動視窗。發現網上還很少這道題的解法,於是簡單整理了一下。題目雖然叫氣球遊戲,但是本質其實還是“最小覆蓋字串”。
2 題目描述
小Q在進行射擊氣球的遊戲,如果小Q在連續T槍中打爆了所有顏色的氣球,將得到一隻QQ公仔作為獎勵。(每種顏色的氣球至少被打爆一隻)。
這個遊戲中有m種不同顏色的氣球,編號1到m。小Q一共有n發子彈,然後連續開了n槍。小Q想知道在這n槍中,打爆所有顏色的氣球最少用了連續幾槍?
- 輸入描述:
第一行兩個空格間隔的整數數n,m。n<=1000000 m<=2000
第二行一共n個空格間隔的整數,分別表示每一槍打中的氣球的顏色,0表示沒打中任何顏色的氣球。
- 輸出描述:
一個整數表示小Q打爆所有顏色氣球用的最少槍數。如果小Q無法在這n槍打爆所有顏色的氣球,則輸出-1
- 示例1
輸入:
12 5
2 5 3 1 3 2 4 1 0 5 4 3
輸出:
6
- 示例2
輸入:
12 5
2 5 3 1 3 2 4 1 5 0 4 3
輸出: 5
3 題解
-
思路:
滑動視窗演算法。先向右不斷擴大視窗,滿足條件是,再從左邊縮小視窗找到最優解。 -
實現:
/**
* @author csh
* @date 2021/5/1
*/
public class BalloonGame {
private Integer balloonGame(int n, int m, int[] balloon) {
// 定義視窗和need
HashMap<Integer, Integer> need = new HashMap<>();
HashMap<Integer, Integer> window = new HashMap<>();
// m種顏色的氣球
for (int i = 1; i <= m; i++)
need.put(i, 1);
// 控制視窗用的指標
int left = 0, right = 0;
// window中滿need條件的個數
int valid = 0;
int res = Integer.MAX_VALUE;
while (right < n) {
// 向右擴大視窗
int num = balloon[right];
right++;
if (need.containsKey(num)) {
window.put(num, window.getOrDefault(num, 0) + 1);
if (window.get(num).equals(need.get(num))) valid++;
}
while (valid == m) {
// 記錄最小視窗
res = Math.min(res, right - left);
// 縮小視窗
int num2 = balloon[left];
left++;
if (need.containsKey(num2)) {
if (window.get(num2).equals(need.get(num2))) valid--;
window.put(num2, window.getOrDefault(num2, 0) - 1);
}
}
}
return res == Integer.MAX_VALUE ? -1 : res;
}
public static void main(String[] args) {
int[] balloon = new int[]{2, 5, 3, 1, 3, 2, 4, 1, 0, 5, 4, 3}; // 答案:6
int[] balloon2 = new int[]{2, 5, 3, 1, 3, 2, 4, 1, 5, 0, 4, 3}; // 答案:5
BalloonGame main = new BalloonGame();
Integer res = main.balloonGame(12, 5, balloon2);
System.out.print("最少需要:" + res);
}
}