iT邦幫忙

2026 iThome 鐵人賽

DAY 30
0
Software Development

快樂演算法系列 第 30

6000 Ada third training 還是很爛 & 56 & 準備回頭記憶

  • 分享至 

  • xImage
  •  

橫軸是時間,bar疊到一起就要併。
「目前這條」和「前面已經合併好的最後一條」。
例如:目前合併結果:[1,3];下一條:[2,6];
因為:下一條 start = 2;目前 end = 3;2 <= 3
表Gantt上有碰到/重疊,所以延長右端:
[1,3] + [2,6]→ [1,6]
再看:目前:[1,6]下一條:[8,10];8 > 6
中間斷掉,所以不能合併,直接新增 [8,10]。

按左端排→從左往右只掃一次→下一條碰得到目前右端就延長,碰不到就開新的一段。

時間:排序:O(n log n)
掃一次:O(n)總共:O(n log n)

如果題目一開始就保證已按 start 排好,那甚至只需要掃一次:O(n)。

Input:[[1,3],[2,6],[8,10]]
Output:[[1,6],[8,10]]

[1,3] 和 [2,6] 重疊→ 合成 [1,6]
[8,10] 沒有跟 [1,6] 重疊→ 留下來

不能安全早停。
例如目前已經:[1,10]後面還有:[8,100]仍必須讀,因為答案要從:[1,10]變[1,100]甚至後面還可能有:[200,300]也必放進答案。

所以每個interval至少要看一次;真正花最多時間的是:sort(...)

一般未排序輸入下,在 comparison-based sorting(比較式排序)的模型裡,O(n log n) 最優標準解。

Sort→read往前掃→write留最後合併結果→overlap就延長,不overlap就寫下一格。

這比剛才另外建立 answer更符合你「不做多餘工作」的原則。

class Solution {
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {//併所有重疊區間
        sort(intervals.begin(), intervals.end());//依start由小到大排序

        int write = 0;//最後一個已合併區間的位置

        for (int read = 1; read < intervals.size(); ++read) {//每個區間只讀一次
            if (intervals[read][0] <= intervals[write][1]) {//下一段開始<=目前結尾表重疊
                intervals[write][1] = max(intervals[write][1], intervals[read][1]); //只更新較遠的end
            } else {//下一段完全分離
                ++write;
                intervals[write] = intervals[read];//把新區間放進答案區域
            }
        }

        intervals.resize(write + 1);//刪掉後面已經不用的區間
        return intervals;//回傳合併完成的結果
    }
};

write =「目前合併後的最後一格放在哪個 index」。
例如排序後:
intervals =
index 0: [1,3]
index 1: [2,6]
index 2: [8,10]

一開始:int write = 0;目前答案區只有:index 0: [1,3]所以 write = 0 指向它。
接著看到 [2,6],有重疊,就直接改:intervals[0] = [1,6]
write 還是 0,因為目前答案還是只有一段。

再看到 [8,10],不重疊:++write;變成:write = 1
然後:intervals[1] = [8,10];

最後答案區就是:
index 0: [1,6]
index 1: [8,10]

read = 現在正在看哪一段;write = 合併後答案目前寫到哪一格。

resize(write + 1) 本身就是把 vector 的「有效長度」縮短,超過新長度的元素會被移除。

intervals =
index 0: [1,6]
index 1: [8,10]
index 2: [8,10] ← 舊資料
index 3: [15,18] ← 舊資料

write = 1表真正答案只到 index 1,也就是前 2 格。
intervals.resize(write + 1);
intervals.resize(2);

become index 0: [1,6];index 1: [8,10]後面的 index 2、3 就被 vector 移除了。

resize(2) = 把 vector 長度改成 2,所以只保留 index 0、1

7.write存的是最後一個答案的index,resize()要的是總共有幾個元素。
例如:write = 0代表最後答案在 index 0,所以其實有:1 個元素
因此:resize(write + 1); // resize(1)
再例如:write = 2
代表答案放到:
index 0;index 1;index 2總共有 3 個元素,
resize(write + 1); // resize(3)

index 從 0 開始,所以「最後 index + 1 = 元素個數」。


上一篇
third training 但還是謹慎起見不要跑爆了 & 62 retrieval
系列文
快樂演算法30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言