氣球游戲-2019騰訊筆試


氣球游戲-2019騰訊筆試

小Q在進行射擊氣球的游戲,如果小Q在連續T槍中打爆了所有顏色的氣球,將得到一只QQ公仔作為獎勵。(每種顏色的球至少被打爆一只)。

這個游戲中有m種不同顏色的氣球,編號1到m。

小Q一共有n發子彈,然后連續開了n槍。

小Q想知道在這n槍中,打爆所有顏色的氣球最少用了連續幾槍?

輸入格式

第一行包含兩個整數nm

第二行包含n個整數,分別表示每一槍打中的氣球的顏色,0表示沒打中任何顏色的氣球。

輸出格式

一個整數表示小Q打爆所有顏色氣球用的最少槍數。

如果小Q無法在這n槍打爆所有顏色的氣球,則輸出-1

數據范圍

1≤n≤\(10^6\),
1≤m≤2000

輸入樣例:

12 5
2 5 3 1 3 2 4 1 0 5 4 3

輸出樣例:

6

樣例解釋

有五種顏色的氣球,編號15

游客從第二槍開始直到第七槍,這連續六槍打爆了5 3 1 3 2 4這幾種顏色的氣球,包含了從15的所有顏色,所以最少槍數為6

解法一:雙指針算法

貪心思想,用指針ij維護區間[i, j],移動j擴大區間使得區間內包含所有顏色氣球,當滿足時,移動i指針使得[i,j]區間變小依然能滿足包含所以顏色的氣球,此時更新一次答案(區間大小);直到遍歷完整個數組。

i,j都只增不減,因此時間復雜度為O(n);需要維護區間內每種氣球的數量,以及一個HashSet 快速判斷區間內氣球的種類數量,或者直接使用HashMap,因此空間復雜度為O(m)

import java.util.*;
public class Main {
    static int search(int[] a, int n, int m) {
        int[] cnt = new int[m+1];
        Set<Integer> set = new HashSet<>();
        int res = -1;
        int i = 0, j = 0;
        while(i <= j && j < n) {
            cnt[a[j]]++;
            if(a[j] != 0) set.add(a[j]);
            if(set.size() >= m) {
                while(i < j) {
                    if(a[i] != 0 && cnt[a[i]] == 1)
                        break;
                    cnt[a[i]]--;
                    i++;
                }
                if(res == -1 || j-i+1 < res) res = j-i+1;
            }
            // System.out.println(i+"---"+j);
            j++;
        }
        return res;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] a = new int[n];
        for(int i=0;  i< n; i++)
            a[i] = sc.nextInt();
        System.out.println(search(a, n, m));
    }
}

解法二、二分查找(較為暴力)

如果沒想到第一種方法,則可以暴力做。顯然,答案一定在區間[m,n]內,二分查找答案,時間復雜度為O(log(n-m))。判斷k是否為答案時間復雜度為O(n),因此整個程序時間復雜度O(nlogn)。大致計算\(10^6 \times \log_2^{10^6}\approx 10^6 \times log_2^{2^{20}}=2 \times 10^7\)

時間上依然可以接受;空間復雜度同上。

import java.util.*;
public class Main {
    static int search(int[] a, int l, int r){
        int m=l, n = r;
        Set<Integer> set = new HashSet<>();
        int[] cnt = new int[m+1];
        for(int i=0; i < n; i++) 
            if(a[i] != 0) 
                set.add(a[i]);
        if(set.size() < m) return -1;

        while(l < r) {
            int mid = (l+r)/2;
            set.clear();
            Arrays.fill(cnt,0);
            for(int i=0; i < n; i++) {
                if(a[i] != 0 && !set.contains(a[i])) 
                    set.add(a[i]);
                cnt[a[i]]++;
                if(i >= mid) {
                    cnt[a[i-mid]]--;
                    if(a[i-mid] != 0 && cnt[a[i-mid]]<= 0)
                        set.remove(a[i-mid]);
                }
                if(set.size() >= m) break;
            }
            if(set.size() >= m)
                r=mid;
            else 
                l=mid+1;
        }
        return l;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        int[] a = new int[n];
        for(int i=0; i < n; i++)
            a[i] = sc.nextInt();
        
        System.out.println(search(a, m, n));
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM