729. 我的日程安排表 I

57 阅读2分钟

题目:
实现一个 MyCalendar 类来存放你的日程安排。如果要添加的日程安排不会造成 重复预订 ,则可以存储这个新的日程安排。

当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生 重复预订 。

日程可以用一对整数 start 和 end 表示,这里的时间是半开区间,即 [start, end), 实数 x 的范围为,  start <= x < end 。

实现 MyCalendar 类:

  • MyCalendar() 初始化日历对象。
  • boolean book(int start, int end) 如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true 。否则,返回 false 并且不要将该日程安排添加到日历中。

算法:
[start1, [start2, end1), end2] 如果start1 < end2 && start2 < end1则说明区间相交。

方法一:模拟

type MyCalendar struct {
    Calendar [][]int
}


func Constructor() MyCalendar {
    return MyCalendar{make([][]int, 0)}
}


func (this *MyCalendar) Book(start int, end int) bool {
    for _, p := range this.Calendar {
        if p[0] < end && start < p[1] {
            return false
        }
    }
    this.Calendar = append(this.Calendar, []int{start, end})
    return true
}

方法二: 线段树

type MyCalendar struct {
   tree, lazy map[int]bool
}


func Constructor() MyCalendar {
    return MyCalendar{
        tree: make(map[int]bool),
        lazy: make(map[int]bool),
    }
}


func (this *MyCalendar) Book(start int, end int) bool {
    if this.query(start, end - 1, 0, 1e9, 1) {
        return false
    }
    this.update(start, end - 1, 0, 1e9, 1)
    return true
}

func (this *MyCalendar) query(start, end, left, right, idx int) bool {
    if end < left || right < start {
        return false
    }
    if this.lazy[idx] {
        return true
    }
    if start <= left && right <= end {
        return this.tree[idx] 
    }
    mid := (left + right) >> 1
    return this.query(start, end, left, mid, 2 * idx) || this.query(start, end, mid + 1, right, 2 * idx + 1) 
}

func (this *MyCalendar) update(start, end, left, right, idx int) {
    if end < left || right < start {
        return 
    }
    if start <= left && right <= end { 
        this.tree[idx] = true
        this.lazy[idx] = true
    } else {
        mid := (left + right) >> 1
        this.update(start, end, left, mid, 2 * idx)
        this.update(start, end, mid + 1, right, 2 * idx + 1)
        this.tree[idx] = true
        if this.lazy[2 * idx] && this.lazy[2 * idx + 1] {
            this.lazy[idx] = true
        }
    }
}

/**
 * Your MyCalendar object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Book(start,end);
 */

线段树二:
这个模板不错,偷了

type MyCalendar struct {
   Left, Right int
   Val, Lazy int
   LeftChild, RightChild *MyCalendar
}


func Constructor() MyCalendar {
    return MyCalendar{
        Left:0,
        Right:1e9,
    }
}

func NewNode(left, right int) *MyCalendar {
    return &MyCalendar{
        Left: left,
        Right: right,
    }
}

func (this *MyCalendar) Book(start int, end int) bool {
    if this.query(start, end -1) > 0 {
        return false
    }
    this.update(start, end - 1, 1)
    return true
}

func (this *MyCalendar) query(start, end int) int {
    //  如果node在区间内
    // 当前节点表示的整个区间在查询目标区间内,返回,和其他的区间加起来
    if start <= this.Left && this.Right <= end {
        return this.Val
    } 
    
    // 为什么要lazycreate呢,因为this的范围可能是[2,9],而query的参数可能是[3,3],所以需要吧this的子节点动态生成出来
    this.lazyCreate()
    // push down
    this.pushdown()
    mid := this.Left + (this.Right - this.Left) / 2 
    if end <= mid {
        return this.LeftChild.query(start, end)
        // 为什么mid == start 不能走这个逻辑?
        // 因为小于等于mid是this的左节点管,大于mid的值是this的右节点管啊
    } else if mid < start {
        return this.RightChild.query(start, end)
    } 

    // 拆分start, end区间求结果
    return  this.LeftChild.query(start, mid) + this.RightChild.query(mid + 1, end)
}

func (this *MyCalendar) lazyCreate() {
	mid := this.Left + (this.Right - this.Left) / 2 
    if this.LeftChild == nil {
        this.LeftChild = NewNode(this.Left, mid)
    }
    if this.RightChild == nil {
        this.RightChild = NewNode(mid + 1, this.Right)
    }
}

func (this *MyCalendar) pushdown() {
	if this.Lazy == 0 {
		return
	}
    this.LeftChild.Val =  this.LeftChild.Val + (this.LeftChild.Right - this.LeftChild.Left + 1) * this.Lazy
    this.RightChild.Val =  this.RightChild.Val + (this.RightChild.Right - this.RightChild.Left + 1) * this.Lazy
    this.LeftChild.Lazy = this.Lazy
    this.RightChild.Lazy = this.Lazy
    this.Lazy = 0
}
func (this *MyCalendar) update(start, end, val int) {
    if end < this.Left || this.Right < start {
        return
    }

    if start <= this.Left && this.Right <= end {
        this.Lazy = val
        this.Val = (this.Right - this.Left + 1) * val 
    } else {
        this.lazyCreate()
        this.pushdown()
        this.LeftChild.update(start, end, val)
        this.RightChild.update(start, end, val)
        this.Val = this.LeftChild.Val + this.RightChild.Val
    }
}

/**
 * Your MyCalendar object will be instantiated and called as such:
 * obj := Constructor();
 * param_1 := obj.Book(start,end);
 */