[英雄星球六月集训LeetCode解题日报] 第22日 有序集合

日报

  • 刚写的珂朵莉板子,没想到这么快就用上了。
  • 1、3题用的珂朵莉。
  • 注意这俩题其实都没有大范围assign,正解大概都不应该是珂朵莉,不过反正过了。

题目

一、 732. 我的日程安排表 III

链接: 732. 我的日程安排表 III

1. 题目描述

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

给你一些日程安排 [start, end) ,请你在每个日程安排添加后,返回一个整数 k ,表示所有先前日程安排会产生的最大 k 次预订。

实现一个 MyCalendarThree 类来存放你的日程安排,你可以一直添加新的日程安排。

MyCalendarThree() 初始化对象。
int book(int start, int end) 返回一个整数 k ,表示日历中存在的 k 次预订的最大值。

2. 思路分析

这题的兄弟三题在我的笔记里用过很多次,动态开点线段树套的最快。
但珂朵莉能做!比线段树快!
优化完比官解还快!这很柯学!
在这里插入图片描述

3. 代码实现
class ODTNode:
    def __init__(self,l,r,v):
        self.l,self.r,self.v = l,r,v
    def __lt__(self,other):
        return self.l<other.l
    def jiebao(self):
        return self.l,self.r,self.v
class ODT:
    def __init__(self,l,r,v):
        from sortedcontainers import SortedList
        self.tree = SortedList([ODTNode(l,r,v)])
        

    def split(self,pos):
        """ 在pos位置切分,返回左边界l为pos的线段下标
        """
        tree = self.tree
        p = tree.bisect_left(ODTNode(pos,0,0))
        if p != len(tree) and tree[p].l == pos:
            return p 
        p -= 1
        l,r,v = tree[p].jiebao()
        tree[p].r = pos-1
        # tree.pop(p)
        # tree.add(ODTNode(l,pos-1,v))
        tree.add(ODTNode(pos,r,v))
        return p+1
       
    def assign(self,l,r,v):
        """
        把[l,r]区域全变成val
        """
        tree = self.tree
        begin = self.split(l)
        end = self.split(r+1)
        for i in range(begin,end):
            tree.pop(begin)
        tree.add(ODTNode(l,r,v))


    # 以下操作全是暴力,寄希望于这里边元素不多。
    def add_interval(self,l,r,val):
        """区间挨个加
        """
        tree = self.tree
        begin = self.split(l)
        end = self.split(r+1)
        m = 0
        for i in range(begin,end):
            tree[i].v += val
            m = max(m,tree[i].v)
        return m

    def query_max(self,l,r):
        """
        查找x,y区间的最大值
        """        
        begin = self.split(l)
        end = self.split(r+1)
        return max(node.v for node in self.tree[begin:end])
    def query_all_max(self,):
        """
        查找x,y区间的最大值
        """        
        begin = self.split(0)
        end = self.split(10**9+1)
        return max(node.v for node in self.tree[begin:end])
class MyCalendarThree:

    def __init__(self):
        self.odt = ODT(0,10**9,0)
        self.m = 0


    def book(self, start: int, end: int) -> int:        
        self.m = max(self.m,self.odt.add_interval(start,end-1,1))
        return self.m
        # return self.odt.query_all_max()

二、 895. 最大频率栈

链接: 895. 最大频率栈

1. 题目描述

设计一个类似堆栈的数据结构,将元素推入堆栈,并从堆栈中弹出出现频率最高的元素。

实现 FreqStack 类:

  • FreqStack() 构造一个空的堆栈。
  • void push(int val) 将一个整数 val 压入栈顶。
  • int pop() 删除并返回堆栈中出现频率最高的元素。
    • 如果出现频率最高的元素不只一个,则移除并返回最接近栈顶的元素。
2. 思路分析

没想到什么好办法,硬做。

  • cnt储存每个数的计数;max_f储存当前最大频率是几;f_x储存每个频率经过的数字,用哈希表储存栈
  • 入栈时,计数+1,频率更新,这个数的新频率栈入栈。
  • 出栈时,检查当前最大频率对应的栈是否空,空的话降低到非空那个,然后出栈,更新频率。
3. 代码实现
class FreqStack:

    def __init__(self):
        self.cnt = Counter()
        self.f_x = defaultdict(list)
        self.max_f = 0


    def push(self, val: int) -> None:
        cnt = self.cnt 
        
        cnt[val] +=1
        self.max_f = max(self.max_f,cnt[val])
        self.f_x[cnt[val]].append(val)


    def pop(self) -> int:
        f_x = self.f_x
        while not f_x[self.max_f]:
            self.max_f -=1
        x = f_x[self.max_f].pop()
        self.cnt[x] -= 1
        return x        

三、 352. 将数据流变为多个不相交区间

链接: 352. 将数据流变为多个不相交区间

1. 题目描述

在这里插入图片描述

2. 思路分析

用数组映射一下,这就是个简单的线段合并。
我就是要用柯学做!
回头有空用数组写一下看看。

3. 代码实现
class ODTNode:
    def __init__(self,l,r,v):
        self.l,self.r,self.v = l,r,v
    def __lt__(self,other):
        return self.l<other.l
    def jiebao(self):
        return self.l,self.r,self.v
class ODT:
    def __init__(self,l,r,v):
        from sortedcontainers import SortedList
        self.tree = SortedList([ODTNode(l,r,v)])        

    def split(self,pos):
        """ 在pos位置切分,返回左边界l为pos的线段下标
        """
        tree = self.tree
        p = tree.bisect_left(ODTNode(pos,0,0))
        if p != len(tree) and tree[p].l == pos:
            return p 
        p -= 1
        l,r,v = tree[p].jiebao()
        tree[p].r = pos-1
        # tree.pop(p)
        # tree.add(ODTNode(l,pos-1,v))
        tree.add(ODTNode(pos,r,v))
        return p+1
       
    def assign(self,l,r,v):
        """
        把[l,r]区域全变成val
        """
        tree = self.tree
        begin = self.split(l)
        end = self.split(r+1)
        for i in range(begin,end):
            tree.pop(begin)
        tree.add(ODTNode(l,r,v))


    # 以下操作全是暴力,寄希望于这里边元素不多。
    def add_interval(self,l,r,val):
        """区间挨个加
        """
        tree = self.tree
        begin = self.split(l)
        end = self.split(r+1)
        m = 0
        for i in range(begin,end):
            tree[i].v += val
            m = max(m,tree[i].v)
        return m

    def query_max(self,l,r):
        """
        查找x,y区间的最大值
        """        
        begin = self.split(l)
        end = self.split(r+1)
        return max(node.v for node in self.tree[begin:end])
    def query_all_max(self,):
        """
        查找x,y区间的最大值
        """        
        begin = self.split(0)
        end = self.split(10**9+1)
        return max(node.v for node in self.tree[begin:end])
    def query_all_intervals(self):
        tree = self.tree
        lines = []
        l = r = -1
        for node in tree :
            if node.v == 0:
                if l != -1:
                    lines.append([l,r])
                    l = -1
            else:
                if l == -1:
                    l = node.l 
                r = node.r

        return lines

            

class SummaryRanges:

    def __init__(self):
        self.odt = ODT(0,10**4+1,0)


    def addNum(self, val: int) -> None:
        self.odt.assign(val,val,1)


    def getIntervals(self) -> List[List[int]]:
        return self.odt.query_all_intervals()

参考链接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值