T1:我的日程 安排表(I)
实现一个 MyCalendar 类来存放你的日程安排。如果要添加的日程安排不会造成 重复预订 ,则可以存储这个新的日程安排。
当两个日程安排有一些时间上的交叉时(例如两个日程安排都在同一时间内),就会产生 重复预订 。
日程可以用一对整数 start 和 end 表示,这里的时间是半开区间,即 [start, end), 实数 x 的范围为, start <= x < end 。
实现 MyCalendar 类:
MyCalendar() 初始化日历对象。boolean book(int start, int end) 如果可以将日程安排成功添加到日历中而不会导致重复预订,返回 true 。否则,返回 false 并且不要将该日程安排添加到日历中。解:
1.关键 :
(1)利用 map 存储下 每一个时间段
(2)主要 判断是否 发生 交叉 不好处理 , 朴素的想法就是 遍历 map
改进:
其实 ,答案的 判断 时间段是否 交叉的 方法 更加 好:
2个时间段 发生交叉 --iff -- start1 < end2 && start2 < end1 ,反正就是 2者的 开始 时间 都小于 另外一方的 结束 时间
2.代码:
class MyCalendar {
public://关键 是 怎么 判断 2个时间 是否 产生交叉//最 简单的 方法就是 遍历!暴力搜索 -- 利用map进行存储unordered_map Map;MyCalendar() {}bool book(int start, int end) {for(auto it:Map){if((start>= it.first && start< it.second) || (end >it.first && end<=it.second) || (start<=it.first && end>it.second)) //少考虑了一种包含情况{return false;}}Map[start] =end;return true;}
};
T2: 检测 是否 发生时间段的 3重 重叠 的 时间安排表
实现一个 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)
解:
1.关键:(利用 朴素的 暴力 搜索法)
(1)利用 2个 vector容器, Vec1 用于 存储 已经遍历过的 时间段
Vec2 用于 存储 发生了 时间2次 重叠的时间段 ,Vec中的元素都是 pair
//不能用Map,因为 可能 有 相同的 开始 时间
(2)每次 添加一个 新的 时间段, 首先 搜索 是否 和 Map2中的某个时间段 发生重叠,如果重叠直接返回 false
(3)然后 搜索 是否和第一次 遍历的 时间段的Map1中的 某个时间段 发生 重叠(利用时间重叠判断条件) , 然后 将真正重叠的 那个时间段 冲出到 Map2中
2.代码:
class MyCalendarTwo {
public:MyCalendarTwo() {}bool book(int start, int end) {for (auto &[l, r] : overlaps) {if (l < end && start < r) {return false;}}for (auto &[l, r] : booked) {if (l < end && start < r) {overlaps.emplace_back(max(l, start), min(r, end));}}booked.emplace_back(start, end);return true;}
private:vector> booked;vector> overlaps;
};
解法二: 利用 “插旗子计数法”
1.关键:
(1)必须 利用 有序 map,因为 遍历的 时候 必须从前往后 有序遍历
(2)如果 某个时刻 计数max >=3 说明 存储了 这个日程安排之后 会出现3次重叠的情况
2.代码:
class MyCalendarTwo {
public:MyCalendarTwo() {}bool book(int start, int end) {//法二: 利用“插旗子”计数的思想int max = 0;cnt[start]++;cnt[end]--; //初始值 都是0for(auto &[_,flag] : cnt){max+=flag;if(max > 2){cnt[start]--;cnt[end]++;return false;}}return true;}map cnt;
};
T3: 我的日程 安排表 version3
当 k 个日程安排有一些时间上的交叉时(例如 k 个日程安排都在同一时间内),就会产生 k 次预订。
给你一些日程安排 [start, end) ,请你在每个日程安排添加后,返回一个整数 k ,表示所有先前日程安排会产生的最大 k 次预订。
实现一个 MyCalendarThree 类来存放你的日程安排,你可以一直添加新的日程安排。
MyCalendarThree() 初始化对象。int book(int start, int end) 返回一个整数 k ,表示日历中存在的 k 次预订的最大值。解:
1.关键:
(1) 利用 讨论区的 “插旗子”计数 思想:
举例子 [10, 15) [12, 18)
插旗子 计数 <10, 1> <12, 1> <15, -1> <18, -1> 如果 两个Interval 不相交,则 连续两个 插旗计数的 和 必然等于零,一个+1,一个-1
如果 两个 Interval 相交,则 连续两个插旗计数 的和 必然大于0,一个+1,一个+1
(2)总之 , 相对于之前 就是 多了 一个 打擂台的 环节 获得 最终的 最大值 ans ,然后 返回即可
2.代码:
class MyCalendarThree {
public:MyCalendarThree() {}int book(int startTime, int endTime) {//借助 之前的解法 , 利用“插旗子计数”的 思想进行求解int max_num = 0;cnt[startTime]++;cnt[endTime]--;int ans=0;for(auto &[_,flag]:cnt){max_num+=flag;ans = max(max_num,ans);}return ans;}map cnt;
};
T4:简单 2层循环: excel的 某个范围内的 所以 下标
Excel 表中的一个单元格 (r, c) 会以字符串 " 的形式进行表示,其中:
即单元格的列号 c 。用英文字母表中的 字母 标识。 1 列用 'A' 表示,第 2 列用 'B' 表示,第 3 列用 'C' 表示,以此类推。|
即单元格的行号 r 。第 r 行就用 整数 r 标识。给你一个格式为 " 的字符串 s ,其中 表示 c1 列, 表示 r1 行, 表示 c2 列, 表示 r2 行,并满足 r1 <= r2 且 c1 <= c2 。
找出所有满足 r1 <= x <= r2 且 c1 <= y <= c2 的单元格,并以列表形式返回。单元格应该按前面描述的格式用 字符串 表示,并以 非递减 顺序排列(先按列排,再按行排)。
解:
1.关键:
(1) 字母作为 外层循环 ,数字 作为 内层循环
2.代码:
class Solution {
public:vector cellsInRange(string s) {//其实 就是从 第一列 开始 ,一次 将每一列 加入到 vec中//2层循环即可//(1)先取出 字母 和 数字char alpha1 = s[0];char alpha2 = s[3];char num1 = s[1];char num2 = s[4];vector ans;//(2)2层循环for(char ch=alpha1 ; ch<=alpha2 ; ch++){for(char i=num1 ;i <=num2 ;i++){//以string的形式返回string str;str = str+ch + i;ans.push_back(str);}}return ans;}
};
T5:最长 数对 链
给你一个由 n 个数对组成的数对数组 pairs ,其中 pairs[i] = [lefti, righti] 且 lefti < righti 。
现在,我们定义一种 跟随 关系,当且仅当 b < c 时,数对 p2 = [c, d] 才可以跟在 p1 = [a, b] 后面。我们用这种形式来构造 数对链 。
找出并返回能够形成的 最长数对链的长度 。
你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
解:
1.关键:
(1)一眼 看出 这个题目 就是 会议安排的 问题 ,利用 贪婪法 就可以 得到 最多的 会议安排个数
(2)先 对 pairs二维数组中的 end时间点 进行归并排序
(3)然后 每次选出 不冲突的 结束 时间最早的 那个即可
2.代码:
class Solution {
public:int findLongestChain(vector>& pairs) {//返回 最长数对链的 长度//悟: 这不就是 那个 经典贪婪法 的 会议安排个数 最多的 问题吗//先 按照 最先end的时间 进行 排序 ,然后 每次 选出 最先end但是 又不//冲突的 会议,cnt++//(1)练习 : 利用归并排序对 pairs的 数组进行排序pairs = merge_sort(pairs); //此时的pairs已经按照end时间进行了排序,然后挑选//(2)每次挑选 最先结束的 那个会议 int last_end = -9999;int cnt= 0;int size= pairs.size();for(int i=0;i<=size-1;i++){if(pairs[i][0] > last_end){cnt++;last_end = pairs[i][1]; //贪婪法}}return cnt;}vector> merge_sort(vector>& pairs){//这是一个 递归函数 , 一直分治到 1个元素 作为出口if(pairs.size() == 1){return pairs;}// 左边为 向下 取整的一半 ,右边是另一半vector> left;vector> right;int size = pairs.size();int half = size/2;for(int i=0;i> merge(vector>& a,vector>& b){vector> res;//这个函数的 参数是 2个有序的顺序表 , 只要合并为一个有序的顺序表即可int size1=a.size();int size2=b.size();int i=0,j=0;while(i<=size1-1 && j<=size2-1){if(a[i][1] <= b[j][1]){res.push_back(a[i]);i++;}else{res.push_back(b[j]);j++;}}//收尾:if(i>size1-1){while(j<=size2-1){res.push_back(b[j]);j++;}}if(j>size2-1){while(i<=size1-1){res.push_back(a[i]);i++;}}//return res;}
};
剩下 都是 一些 SQL 数据库的 题目 ,我就 不参和了 。。。