分割數組爲連續子序列

flag

軟件學院大三黨,每天一道算法題,第34天

題目介紹

輸入一個按升序排序的整數數組(可能包含重複數字),你需要將它們分割成幾個子序列,其中每個子序列至少包含三個連續整數。返回你是否能做出這樣的分割?
在這裏插入圖片描述

思路

我們把 3 個或更多的連續數字稱作 chain。

我們從左到右考慮每一個數字 x,如果 x 可以被添加到當前的 chain 中,我們將 x 添加到 chain 中,這一定會比創建一個新的 chain 要更好。

爲什麼呢?如果我們以 x 爲起點新創建一個 chain ,這條新創建更短的鏈是可以接在之前的鏈上的,這可能會幫助我們避免創建一個從 x 開始的長度爲 1 或者 2 的短鏈。
算法

我們將每個數字的出現次數統計好,記 tails[x] 是恰好在 x 之前結束的鏈的數目。

現在我們逐一考慮每個數字,如果有一個鏈恰好在 x 之前結束,我們將 x 加入此鏈中。否則,如果我們可以新建立一條鏈就新建。

我們可以優化額外空間到 O(1)O(1),因爲我們可以像 方法 1 一樣統計數字的出現次數,而且我們只需要知道最後 3 個數字的出現次數即可。

關鍵代碼

public class Main {
    public boolean isPossible(int[] nums) {
        Counter count = new Counter();
        Counter tails = new Counter();//tails[x] 是恰好在 x 之前結束的鏈的數目。
        for (int x: nums)
            count.add(x, 1);

        for (int x: nums) {
            if (count.get(x) == 0) {
                continue;
            }
            else if (tails.get(x) > 0) {
                tails.add(x, -1);
                tails.add(x+1, 1);
            }
            else if (count.get(x+1) > 0 && count.get(x+2) > 0) {
                count.add(x+1, -1);
                count.add(x+2, -1);
                tails.add(x+3, 1);
            }
            else {
                return false;
            }
            count.add(x, -1);
        }
        return true;
    }

}
class Counter extends HashMap<Integer, Integer> {
    public int get(int k) {//存在就返回值,不存在返回0
        return containsKey(k) ? super.get(k) : 0;
    }

    public void add(int k, int v) {//把k的值加上v
        put(k, get(k) + v);
    }
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章