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