• 212. go语言堆实现


    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()
    }
    
  • 相关阅读:
    Android
    Android
    Android
    Android
    Android
    【工作中学习】CreateProcessAsUser失败,错误码:1314
    【Angular JS】网站使用社会化评论插件,以及过程中碰到的坑
    【Angular JS】正确调用JQuery与Angular JS脚本
    【工作】Proxy Server的优化
    AWS ELB Sticky Session有问题?别忘了AWSELB cookie
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/15687535.html
Copyright © 2020-2023  润新知