1. 我的日历安排 II
实现一个 MyCalendar 类来存放你的日程安排。如果要添加的时间内不会导致三重预订时,则可以存储这个新的日程安排。
MyCalendar 有一个 book(int start, int end)方法。它意味着在 start 到 end 时间内增加一个日程安排,注意,这里的时间是半开区间,即 [start, end), 实数 x 的范围为, start <= x < end。
当三个日程安排有一些时间上的交叉时(例如三个日程安排都在同一时间内),就会产生三重预订。
每次调用 MyCalendar.book方法时,如果可以将日程安排成功添加到日历中而不会导致三重预订,返回 true。否则,返回 false 并且不要将该日程安排添加到日历中。
请按照以下步骤调用MyCalendar 类: MyCalendar cal = new MyCalendar(); MyCalendar.book(start, end)
分析:
记录下所有已经预定的课程安排区间与已经预定过两次的课程安排区间,当预定新的区间 [start,end) 时,此时检查当前已经预定过两次的每个日程安排是否与新日程安排冲突。若不冲突,则可以添加新的日程安排。对于两个区间 [s1,e1)[和 [s2,e2),如果二者没有交集,则此时应当满足 s1>=e2s或者 s2>=e1 ,这就意味着如果满足 s1 < e2并且 s2 < e1 时,则两者会产生差集。
首先检测新加入的区间 [start,end) 是否与已经预定过两次的区间有交集,如果没有冲突,则将新加入的区间与已经预定的区间进行检查,求出新增的预定两次的区间。对于两个区间 [s1,e1)和 [s2,e2),则他们之间的交集为[max(s1 ,s2),min(e1,e2))。
class MyCalendarTwo {
List<int[]> booked;
List<int[]> overlaps;
public MyCalendarTwo() {
booked = new ArrayList<int[]>();
overlaps = new ArrayList<int[]>();
}
public boolean book(int start, int end) {
for (int[] arr : overlaps) {
int l = arr[0], r = arr[1];
if (l < end && start < r) {
return false;
}
}
for (int[] arr : booked) {
int l = arr[0], r = arr[1];
if (l < end && start < r) {
overlaps.add(new int[]{Math.max(l, start), Math.min(r, end)});
}
}
booked.add(new int[]{start, end});
return true;
}
}
2. 设置交集大小至少为2
一个整数区间 [a, b] ( a < b ) 代表着从 a 到 b 的所有连续整数,包括 a 和 b。
给你一组整数区间intervals,请找到一个最小的集合 S,使得 S 里的元素与区间intervals中的每一个整数区间都至少有2个元素相交。
输出这个最小集合S的大小。
分析:
首先按照右边界大小对数组进行排序。排序问题可能习惯性的从左边考虑,这个问题可能就别扭到这里了。尽量靠右拿,才最有可能落到后续的区间里。
class Solution {
public int intersectionSizeTwo(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[1] - b[1]);
int a = intervals[0][1] - 1;
int b = intervals[0][1];
int ans = 2;
for (int i = 1; i < intervals.length; i++) {
int[] ints = intervals[i];
int l = ints[0], r = ints[1];
if (l > b) {
ans += 2;
a = r - 1;
b = r;
} else if (l == b || l > a) {
ans += 1;
a = b;
b = r;
}
}
return ans;
}
}
3. 和为K的子数组
给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。
分析:
使用前缀和来解决。假设pre[i]为数组前i个位置的和, pre[j]为数组前j个位置的和, 如果pre[j] - pre[i]=k
则(i,j)的区间就是要找的区间。使用哈希表来记录在遍历到i位置之前前缀和出现的次数。
class Solution {
public int subarraySum(int[] nums, int k) {
int count = 0, pre = 0;
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0 , 1);
for (int i = 0; i < nums.length; i++) {
pre += nums[i];
if (map.containsKey(pre - k)){
count += map.get(pre - k);
}
map.put(pre, map.getOrDefault(pre, 0)+1);
}
return count;
}
}