3408. Design Task Manager | LeetCode | Swift

vc7-avatar-img
發佈於LeetCode
更新 發佈閱讀 11 分鐘

每日一題

日期

2025/9/18

前置

LeetCode 有引入 swift-collections 1.1.4 ,這篇就會用其中的 Heap 資料結構而不自己實作。

Ref: https://support.leetcode.com/hc/en-us/articles/360011833974-What-are-the-environments-for-the-programming-languages

經過多次改善、簡化後最快有到 118ms

raw-image

想法與資料結構

swift-collections 提供的 Heap 無法有效率地移除,像是需要使用 unordered 陣列、找到目標物、最後再重新生成 Heap 。時間複雜度和空間複雜度都可觀之外,寫出來的程式碼也變得複雜難讀。

於是根據題意: taskId 是唯一,這篇的資料結構就可以這樣應用:

  • HashMap: 維持 taskId: task pairs,可以幫助我們快速以 taskId 取得 task 。 (O(1))
  • Heap: 維持排序,無論是刪或加, task 都只進不出。當要進行 execTop() 過程,只要 pop 到過時的 task 時直接忽略即可。
class TaskManager {
// 用來 Heap 排序的容器,其中的元素只增不減。在 pop 時和 taskMap 對照當下 task 的合法性
private var tasks = Heap<Task>()
// 識別現有 Task 的 Map, [taskId: Task]
private var taskMap = [Int: Task]()

/* To be continue */
}

Task 構造

根據題意,

  • priority 相同時,taskId 較大者為大
struct Task: Comparable {
let userId: Int
let taskId: Int
let priority: Int

// MARK: Comparable

static func < (lhs: Task, rhs: Task) -> Bool {
guard lhs.priority != rhs.priority else {
return lhs.taskId < rhs.taskId
}

return lhs.priority < rhs.priority
}
}

新增的核心邏輯

init 裡面、edit 都會用到生成 Task ,插入 Heap, HashMap 的邏輯就集中到這裡

class TaskManager {
/* 省略 */

/// 生成 Task 並插入 HashMap 和 Heap
func add(_ userId: Int, _ taskId: Int, _ priority: Int) {
let task = Task(
userId: userId,
taskId: taskId,
priority: priority
)
tasks.insert(task)
taskMap[task.taskId] = task
}
/* 省略 */
}

初始化

走訪完美一個子陣列,直接呼叫 add 即可

class TaskManager {
/* 省略 */
init(_ tasks: [[Int]]) {
for task in tasks {
add(task[0], task[1], task[2])
}
}
/* 省略 */
}

編輯

在編輯的時候,依據前面提到的處理方式, Heap 裡的 task 只出不進。這邊找到對應的 task 、取用 userId 後新增一個新的 task 。

class TaskManager {
/* 省略 */
func edit(_ taskId: Int, _ newPriority: Int) {
guard let task = taskMap[taskId] else { return }
add(task.userId, taskId, newPriority)
}
/* 省略 */
}

移除

因為 Heap 裡的 task 只出不進,這邊就只需要把 HashMap 裡面 key 為 taskId 的值清除就好了

class TaskManager {
/* 省略 */
func rmv(_ taskId: Int) {
taskMap[taskId] = nil
}
/* 省略 */
}

回傳最大 task 的 userId

因為 Heap 裡的 task 只出不進,所以我們這邊有兩個步驟

  1. 呼叫 popMax 彈出一個 task
  2. 彈出的 task 有在 HashMap 裡,否則忽略, 繼續 1. 彈出下一個最大值
class TaskManager {
/* 省略 */
func execTop() -> Int {
while let top = tasks.popMax() { // 1.
if taskMap[top.taskId] == top { // 2.
taskMap[top.taskId] = nil
return top.userId
}
}
return -1
}
/* 省略 */
}

最終程式碼

class TaskManager {
/// 用來 Heap 排序的容器,其中的元素只增不減
private var tasks = Heap<Task>()
/// 識別現有 Task 的 Map, [taskId: Task]
private var taskMap = [Int: Task]()

init(_ tasks: [[Int]]) {
for task in tasks {
add(task[0], task[1], task[2])
}
}

/// 生成 Task 並插入 HashMap 和 Heap
func add(_ userId: Int, _ taskId: Int, _ priority: Int) {
let task = Task(
userId: userId,
taskId: taskId,
priority: priority
)
tasks.insert(task)
taskMap[task.taskId] = task
}

func edit(_ taskId: Int, _ newPriority: Int) {
guard let task = taskMap[taskId] else { return }
add(task.userId, taskId, newPriority)
}

/// 只移除 HashMap 裡面的元素
func rmv(_ taskId: Int) {
taskMap[taskId] = nil
}

func execTop() -> Int {
while let top = tasks.popMax() {
if taskMap[top.taskId] == top {
taskMap[top.taskId] = nil
return top.userId
}
}
return -1
}
}

struct Task: Comparable {
let userId: Int
let taskId: Int
let priority: Int

// MARK: Comparable

static func < (lhs: Task, rhs: Task) -> Bool {
guard lhs.priority != rhs.priority else {
return lhs.taskId < rhs.taskId
}

return lhs.priority < rhs.priority
}
}



留言
avatar-img
萱寫寫
3會員
19內容數
讀書心得、活動參加心得
萱寫寫的其他內容
2025/09/17
LeetCode 每日一題: 2025/09/17
2025/09/17
LeetCode 每日一題: 2025/09/17
2025/09/16
2025/09/16
2025/09/15
2025/09/15
看更多
你可能也想看
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
賽勒布倫尼科夫以流亡處境回望蘇聯電影導演帕拉贊諾夫的舞台作品,以十段寓言式殘篇,重新拼貼記憶、暴力與美學,並將審查、政治犯、戰爭陰影與「形式即政治」的劇場傳統推到台前。本文聚焦於《傳奇:帕拉贊諾夫的十段殘篇》的舞台美術、音樂與多重扮演策略,嘗試解析極權底下不可言說之事,將如何成為可被觀看的公共發聲。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
柏林劇團在 2026 北藝嚴選,再次帶來由布萊希特改編的經典劇目《三便士歌劇》(The Threepenny Opera),導演巴里・柯斯基以舞台結構與舞台調度,重新向「疏離」進行提問。本文將從觀眾慾望作為戲劇內核,藉由沉浸與疏離的辯證,解析此作如何再次照見觀眾自身的位置。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
本文深入解析臺灣劇團「晃晃跨幅町」對易卜生經典劇作《海妲.蓋柏樂》的詮釋,從劇本歷史、聲響與舞臺設計,到演員的主體創作方法,探討此版本如何讓經典劇作在當代劇場語境下煥發新生,滿足現代觀眾的觀看慾望。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
《轉轉生》為奈及利亞編舞家庫德斯.奧尼奎庫與 Q 舞團創作的當代舞蹈作品,融合舞蹈、音樂、時尚和視覺藝術,透過身體、服裝與群舞結構,回應殖民歷史、城市經驗與祖靈記憶的交錯。本文將從服裝設計、身體語彙與「輪迴」的「誕生—死亡—重生」結構出發,分析《轉轉生》如何以當代目光,形塑去殖民視角的奈及利亞歷史。
Thumbnail
利用文字紀錄,明確寫下自己的採購項目......
Thumbnail
利用文字紀錄,明確寫下自己的採購項目......
Thumbnail
這篇文章描述了作者從兼職開發轉為全職開發的過程,並分享了從混進學界指日可待的積極態度。作者也提及自己在專案製作與個人生活上的矛盾與感想,最後分享了專案管理和敏捷開發相關的文章與影片。
Thumbnail
這篇文章描述了作者從兼職開發轉為全職開發的過程,並分享了從混進學界指日可待的積極態度。作者也提及自己在專案製作與個人生活上的矛盾與感想,最後分享了專案管理和敏捷開發相關的文章與影片。
Thumbnail
列出一套完整的程式 程式設計有許多種方法,不過通常會先列出清單的再逐一執行,這樣會加快程式設計的速度。設計通常會採取順推的辦法。所以順推的程式設計方式就是經歷觀念溝通、系統分析、資料統合、權限管理、頻率與時間、後台管理、畫面設計等等階段後,將框架設計完了以後,先列出一套完整的程式,將所有使用者都確
Thumbnail
列出一套完整的程式 程式設計有許多種方法,不過通常會先列出清單的再逐一執行,這樣會加快程式設計的速度。設計通常會採取順推的辦法。所以順推的程式設計方式就是經歷觀念溝通、系統分析、資料統合、權限管理、頻率與時間、後台管理、畫面設計等等階段後,將框架設計完了以後,先列出一套完整的程式,將所有使用者都確
Thumbnail
題目敘述 題目會給我們一個定義好的類別和function介面,要求我們實作建構子和ping() function來滿足指定的需求。 RecentCounter類別的建構子 建構子應該初始化來電紀錄,內容為空(零筆資料) int ping(int t) t代表來電時刻,單位是毫秒m
Thumbnail
題目敘述 題目會給我們一個定義好的類別和function介面,要求我們實作建構子和ping() function來滿足指定的需求。 RecentCounter類別的建構子 建構子應該初始化來電紀錄,內容為空(零筆資料) int ping(int t) t代表來電時刻,單位是毫秒m
Thumbnail
1.設計與開發 1.1 精明管家系統之儀表板 portfolio 中各標的的持有數量歷史資料,累積的資料量已經逐漸變得太大,原本存在 firestore 同一個 collection 中。因此資料在運算操作績效時,預設期間是 YTD,故將資料拆成每年一個 collection,以加快報表產生速度
Thumbnail
1.設計與開發 1.1 精明管家系統之儀表板 portfolio 中各標的的持有數量歷史資料,累積的資料量已經逐漸變得太大,原本存在 firestore 同一個 collection 中。因此資料在運算操作績效時,預設期間是 YTD,故將資料拆成每年一個 collection,以加快報表產生速度
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News