212. go語言堆實現
阿新 • • 發佈:2021-12-14
630. 課程表 III
在看這道題的題解的時候總結下
package main import ( "container/heap" "sort" ) /* @如寒灬 的評論, https://leetcode-cn.com/u/wanyan/ 這是他的主頁 為了更好的瞭解其貪心原則的使用我們來看看這個例子 例:[[4,6],[5,5],[2,6]] 首先對其結束時間進行排序 [[5,5],[4,6],[2,6]] 排課的起始時間為0,當前已選的課程為[] 選擇第0號課程[5,5] 起始時間變為5,當前已選課程為[[5,5]] 選擇第1號課程[4,6] 由於其結束時間為5+4=9大於其要求的結束時間,因此不可取 好了重點來了,對於這前兩門課程我無論怎麼選,都無法再多選一門課程,那我還不如直接找到其中耗時最長的那麼課程, 如果其耗時比當前課程([4,6])要長,那麼我就用當前課程將其替換, 此時選擇的課程的數目雖然沒有變化,但是起始時間變短了。給後面的課程的安排留下了更為寬闊的空間 用[4,6]替換掉[5,5]課程 起始時間變為5-5+4=4,當前已選課程為[[4,6]] 為什麼當前課程能直接替換掉前面的某一課程? 要能替換掉該課程,則所有的已選課程都要能在規定的End的時間內能學完 假設當前已選課程為[A,B,C,D],然後要加入的課程為E,已知B的持續時長>E的持續時長,是否能使用E來替換掉B ? 對於B之前的資料顯然沒有影響 對於B之後的資料有 CurTime替換前>CurTime替換後 因為 CurTimeB之前+TimeB<EndC => CurTimeB之前+TimeE < EndC 只不過是使用比較小的TimeE將TimeB替換掉了, 也就是時間少了TimeB-TimeE的差值 因此對於B之後的資料也沒有影響,只是CurTime變小,留給之後安排的課程的時間變寬裕了 這個完了之後, 大概說一下go堆的使用: go預設沒有實現具體直接可以使用的結構體給你使用, 比如python裡面的heaq, 以及java中的PriorityQueue優先佇列 而是設定了一個介面供你自己來實現它, 而本身 heap如果要實現一個堆, 需要對內部元素進行比較排序, 所以你自己的 資料型別必須實現sortj介面的Len(), Less(), Swap()方法 Less()這個方式是用來表示生成的是大頂堆還是小頂堆的, 比如 func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }, 輸入的i, j 和比較式的順序, 一致且比較時 使用的<那麼他就是一個小丁堆, 如果把return h[i] > h[j]改為這樣, 那麼他就是大頂堆. Swap() 方法是交換元素的方式, 主要在升序以及降序時使用. 同時heap自己的介面定義如下, sort.Interface 需要一個實現了sort介面的結構, 也就是上面我說的那個實現了sort介面的一個結構 比較典型的是哪些呢?sort.IntSlice, 可以看他的原始碼, 發現它本身就實現類sort介面的方法 type Interface interface { sort.Interface Push(x interface{}) // add x as element Len() Pop() interface{} // remove and return element Len() - 1. } 如果我們想定義一個自己的堆: 1. 定義我們要用的結構 type IntHeap []int 2. 實現sort方法 func (h IntHeap) Len() int { return len(h) } func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] } func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } 3.實現heap的Push, 和Pop方法介面 func (h *IntHeap) Push(x interface{}) { // Push and Pop use pointer receivers because they modify the slice's length, // not just its contents. *h = append(*h, x.(int)) } func (h *IntHeap) Pop() interface{} { old := *h n := len(old) x := old[n-1] *h = old[0 : n-1] return x } 4. 使用heap操作我們自己的堆就可以了 func main() { h := &IntHeap{2, 1, 5} heap.Init(h) heap.Push(h, 3) fmt.Printf("minimum: %d\n", (*h)[0]) for h.Len() > 0 { fmt.Printf("%d ", heap.Pop(h)) } } */ type Heap struct { sort.IntSlice } func (h Heap) Less(i, j int) bool { return h.IntSlice[i] > h.IntSlice[j] // less比較反過來之後, 會導致堆變成一個大頂堆, 最小的元素跑到最後面去 } func (h *Heap) Push(x interface{}) { h.IntSlice = append(h.IntSlice, x.(int)) } func (h *Heap) Pop() interface{} { a := h.IntSlice x := a[len(a)-1] h.IntSlice = a[:len(a)-1] return x } func scheduleCourse(courses [][]int) int { // 對courses進行排序將, lastDayi 小的放前面 sort.Slice(courses, func(i, j int) bool { return courses[i][1] < courses[j][1] }) q := &Heap{} q.Swap(1, 2) total := 0 for _, course := range courses { t1, t2 := course[0], course[1] if total+t1 <= t2 { total += t1 heap.Push(q, t1) } else if q.Len() > 0 && q.IntSlice[0] > t1 { total -= q.IntSlice[0] total += t1 q.IntSlice[0] = t1 // 因為現在是大頂堆, go中的堆,直接將最大值覆蓋掉 heap.Fix(q, 0) // Fix方法相當於, 呼叫了一次heap中的up方法, 等價於heap.remove(q, i), heap.Push(q, t1) } } return q.Len() }