• 2022-6-22 我的日程安排表III,最大频率栈,将数据流变为多个不相交区间


    1. 我的日程安排表 III

    A k-booking happens when k events have some non-empty intersection (i.e., there is some time that is common to all k events.)

    You are given some events [start, end), after each given event, return an integer k representing the maximum k-booking between all the previous events.

    Implement the MyCalendarThree class:

    • MyCalendarThree() Initializes the object.
    • int book(int start, int end) Returns an integer k representing the largest integer such that there exists a k-booking in the calendar.

    Example 1

    Input
    ["MyCalendarThree", "book", "book", "book", "book", "book", "book"]
    [[], [10, 20], [50, 60], [10, 40], [5, 15], [5, 10], [25, 55]]
    Output
    [null, 1, 1, 2, 3, 3, 3]
    
    Explanation
    MyCalendarThree myCalendarThree = new MyCalendarThree();
    myCalendarThree.book(10, 20); // return 1, The first event can be booked and is disjoint, so the maximum k-booking is a 1-booking.
    myCalendarThree.book(50, 60); // return 1, The second event can be booked and is disjoint, so the maximum k-booking is a 1-booking.
    myCalendarThree.book(10, 40); // return 2, The third event [10, 40) intersects the first event, and the maximum k-booking is a 2-booking.
    myCalendarThree.book(5, 15); // return 3, The remaining events cause the maximum K-booking to be only a 3-booking.
    myCalendarThree.book(5, 10); // return 3
    myCalendarThree.book(25, 55); // return 3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Constraints:

    • 0 <= start < end <= 10^9
    • At most 400 calls will be made to book.

    代码 1 [差分数组]

    class MyCalendarThree {
    private:
        map<int, int> mp;
    public:
        MyCalendarThree() {}
    
        int book(int start, int end) {
            ++mp[start], --mp[end];
            int result = 0, sum = 0;
            for (auto it = mp.begin(); it != mp.end(); ++it) {
                sum += it->second;
                result = max(result, sum);
            }
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    代码 2 [线段树]

    class MyCalendarThree:
    
        def __init__(self):
            self.tree = defaultdict(int)
            self.lazy = defaultdict(int)
    
        def update(self, start: int, end: int, l: int, r: int, idx: int):
            if r < start or end < l:
                return
            if start <= l and r <= end:
                self.tree[idx] += 1
                self.lazy[idx] += 1
            else:
                mid = (l + r) >> 1
                self.update(start, end, l, mid, idx * 2)
                self.update(start, end, mid + 1, end, idx * 2 + 1)
                self.tree[idx] = self.lazy[idx] + max(self.tree[idx * 2], self.tree[idx * 2 + 1])
    
        def book(self, start: int, end: int) -> int:
            self.update(start, end - 1, 0, 10 ** 9, 1)
            return self.tree[1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    2. 最大频率栈

    Design a stack-like data structure to push elements to the stack and pop the most frequent element from the stack.

    Implement the FreqStack class:

    • FreqStack() constructs an empty frequency stack.
    • void push(int val) pushes an integer val onto the top of the stack.
    • int pop() removes and returns the most frequent element in the stack.
      • If there is a tie for the most frequent element, the element closest to the stack’s top is removed and returned.

    Example 1

    Input
    ["FreqStack", "push", "push", "push", "push", "push", "push", "pop", "pop", "pop", "pop"]
    [[], [5], [7], [5], [7], [4], [5], [], [], [], []]
    Output
    [null, null, null, null, null, null, null, 5, 7, 5, 4]
    
    Explanation
    FreqStack freqStack = new FreqStack();
    freqStack.push(5); // The stack is [5]
    freqStack.push(7); // The stack is [5,7]
    freqStack.push(5); // The stack is [5,7,5]
    freqStack.push(7); // The stack is [5,7,5,7]
    freqStack.push(4); // The stack is [5,7,5,7,4]
    freqStack.push(5); // The stack is [5,7,5,7,4,5]
    freqStack.pop();   // return 5, as 5 is the most frequent. The stack becomes [5,7,5,7,4].
    freqStack.pop();   // return 7, as 5 and 7 is the most frequent, but 7 is closest to the top. The stack becomes [5,7,5,4].
    freqStack.pop();   // return 5, as 5 is the most frequent. The stack becomes [5,7,4].
    freqStack.pop();   // return 4, as 4, 5 and 7 is the most frequent, but 4 is closest to the top. The stack becomes [5,7].
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Constraints:

    • 0 <= val <= 10^9
    • At most 2 * 10^4 calls will be made to push and pop.
    • It is guaranteed that there will be at least one element in the stack before calling pop.

    代码

    class FreqStack(object):
    
        def __init__(self):
            self.freq = collections.Counter()
            self.group = collections.defaultdict(list)
            self.maxfreq = 0
    
        def push(self, x):
            f = self.freq[x] + 1
            self.freq[x] = f
            if f > self.maxfreq:
                self.maxfreq = f
            self.group[f].append(x)
    
        def pop(self):
            x = self.group[self.maxfreq].pop()
            self.freq[x] -= 1
            if not self.group[self.maxfreq]:
                self.maxfreq -= 1
    
            return x
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3. 将数据流变为多个不相交区间

    给你一个由非负整数 a1, a2, ..., an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表。

    实现 SummaryRanges 类:

    • SummaryRanges() 使用一个空数据流初始化对象。
    • void addNum(int val) 向数据流中加入整数 val
    • int[][] getIntervals() 以不相交区间 [starti, endi] 的列表形式返回对数据流中整数的总结。

    Example 1

    输入:
    ["SummaryRanges", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals", "addNum", "getIntervals"]
    [[], [1], [], [3], [], [7], [], [2], [], [6], []]
    输出:
    [null, null, [[1, 1]], null, [[1, 1], [3, 3]], null, [[1, 1], [3, 3], [7, 7]], null, [[1, 3], [7, 7]], null, [[1, 3], [6, 7]]]
    
    解释:
    SummaryRanges summaryRanges = new SummaryRanges();
    summaryRanges.addNum(1);      // arr = [1]
    summaryRanges.getIntervals(); // 返回 [[1, 1]]
    summaryRanges.addNum(3);      // arr = [1, 3]
    summaryRanges.getIntervals(); // 返回 [[1, 1], [3, 3]]
    summaryRanges.addNum(7);      // arr = [1, 3, 7]
    summaryRanges.getIntervals(); // 返回 [[1, 1], [3, 3], [7, 7]]
    summaryRanges.addNum(2);      // arr = [1, 2, 3, 7]
    summaryRanges.getIntervals(); // 返回 [[1, 3], [7, 7]]
    summaryRanges.addNum(6);      // arr = [1, 2, 3, 6, 7]
    summaryRanges.getIntervals(); // 返回 [[1, 3], [6, 7]]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Constraints:

    • 0 <= val <= 10^4
    • 最多调用 addNumgetIntervals 方法 3 * 10^4

    题解

    方法:有序哈希 + 位图

    执行 void addNum(int val) 操作时具有以下两种情况:

    • 情况一:val 在前序操作已经插入过,直接跳过;
    • 情况二:val 在前序操作中没有出现过,此时直接新建一个区间 [val, val],如果存在相邻区间,则合并这两个区间。

    实现方法:

    • 在情况一需要查找元素是否存在,情况二中需要查找相邻区间边界元素是否存在,因此可以用位图快速查找。
    • 需要记录区间边界,可以采用有序哈希,对于区间 [left, right] ,可以使用 map[left]=rightmap[right]=left 记录。

    实现细节:

    • 对于区间 [val, val] 需要考虑与 [left, val-1][val+1, right] 两个区间的合并情况,可以单独声明一个函数 void combine(int mi) 实现 [left, mi][mi+1, right] 区间的合并。
    • 使用 bitset 时需要注意,bitset 中的元素必须不能为负数。
    • 遍历 map 输出结果时,对于 pair<int, int> pi ,只需要输出 pi.first <= pi.second 的数对。

    提交情况:

    • 执行用时:40 ms, 在所有 C++ 提交中击败了96.24%的用户

    • 内存消耗:32.4 MB, 在所有 C++ 提交中击败了62.10%的用户

    代码

    class SummaryRanges {
    private:
        bitset<10000> bset; // 记录输入数据
        map<int, int> mp; // 记录元素上下边界
    
        void combine(int mi) { // 合并区间 [left, mi], [mi+1, right]
            int left = mp[mi], right = mp[mi + 1];
            mp[left] = right, mp[right] = left;
            if (mi != left) mp.erase(mi);
            if (mi + 1 != right) mp.erase(mi + 1);
        }
    
    public:
        SummaryRanges() {}
    
        void addNum(int val) {
            if (bset.test(val)) return; // 排除数据重复出现情况
            bset.set(val);
            mp[val] = val; // 设置单独区间 [val, val]
            if (bset.test(val + 1)) combine(val); // 如果右侧区间存在, 合并 [val, val], [val+1, right]
            if (val > 0 && bset.test(val - 1)) combine(val - 1); // 如果左侧区间存在, 合并 [left, val-1], [val, right]
        }
    
        vector<vector<int>> getIntervals() {
            vector<vector<int>> result;
            for (auto &it : mp) { // 遍历map, 输出结果
                if (it.first <= it.second) result.push_back({it.first, it.second});
            }
            return result;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
  • 相关阅读:
    web前端期末大作业——HTML+CSS+JavaScript仿王者荣耀游戏网站设计与制作
    Triple-shapelet Networks for Time SeriesClassification(ICDM2020)
    java版直播商城免费搭建平台规划及常见的营销模式+电商源码+小程序+三级分销+二次开发
    Go图片文件按照时间戳如何排序
    Nginx反向代理配置POST请求的nginx.conf相关配置
    APP自动化测试-10.Appium中Desired Capabilities常用参数
    【docker学习记录】docker安装mysql、redis
    【鸿蒙 HarmonyOS 4.0】常用组件:List/Grid/Tabs
    用HTML+CSS+JS做一个漂亮简单的公司网站(JavaScript期末大作业)
    SpringSecurity系列 - 10 传统Web项目表单认证: UsernamePasswordAuthenticationFilter 过滤器
  • 原文地址:https://blog.csdn.net/weixin_43791477/article/details/125417671