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 integerk
representing the largest integer such that there exists ak
-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
Constraints:
0 <= start < end <= 10^9
- At most
400
calls will be made tobook
.
代码 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;
}
};
代码 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]
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 integerval
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].
Constraints:
0 <= val <= 10^9
- At most
2 * 10^4
calls will be made topush
andpop
. - 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
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]]
Constraints:
0 <= val <= 10^4
- 最多调用
addNum
和getIntervals
方法3 * 10^4
次
题解
方法:有序哈希 + 位图
执行 void addNum(int val)
操作时具有以下两种情况:
- 情况一:
val
在前序操作已经插入过,直接跳过; - 情况二:
val
在前序操作中没有出现过,此时直接新建一个区间[val, val]
,如果存在相邻区间,则合并这两个区间。
实现方法:
- 在情况一需要查找元素是否存在,情况二中需要查找相邻区间边界元素是否存在,因此可以用
位图
快速查找。 - 需要记录区间边界,可以采用
有序哈希
,对于区间[left, right]
,可以使用map[left]=right
和map[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;
}
};