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);
}
}