力扣-57-插入区间
采用最直接的思路,if-else
去考虑每一种情况并做出操作(比如找到新区间左端点落在哪个位置,几种情况,然后再去考虑右端点的几种情况)是非常细致繁琐的,以至于很容易出错
考虑三种情况,新区间的两个端点:
- 分别落在两个原有的区间中:保留前一个区间的左端点和后一个区间的右端点,将他俩合并成一个新的区间
- 只有一个端点落在了某个区间:以左端点落在了某个区间为例,就将区间左端点和新区间的右端点合并为一个区间
- 两个端点没有落在任何区间:直接插入作为新的区间成员
另外需要考虑到的是:以上合并的情况中,所有被新合并区间所包含的区间全部都需要删除
编码
- 我需要知道这两个端点有没有落在区间中,如果有,做右端点又分别是谁
需要额外仔细考虑的是各个等于的情况
class Solution { public: vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) { int len = intervals.size(); // 首先确定左端点是否落在了某个区间中 for (int i = 0; i < len; i++) { if (intervals[i][1] >= newInterval[0] && intervals[i][0] <= newInterval[0]) { // 新区间的左端点落在某个区间中 // 不管右端点怎么样,新区间的左端点都会被合并 // 然后去找右端点 for (int j = i + 1; j < len; j++) { if (newInterval[1] > intervals[j][1])intervals.erase(intervals.begin() + j); else if (newInterval[1] >= intervals[j][0]) { // 右端点落在了某个区间中 intervals[i][1] = intervals[j][1];// 合并新区间 break; } // 如果右端点比任何一个区间都大 if (j == len - 1) intervals[i][1] = newInterval[1]; } break; } else if (intervals[i][0] > newInterval[0]) { // 说明确定了左端点没有落在任何一个区间中 // 判断确定了第一个大于左端点的区间,因为右端点一定大于左端点,所以可以接着遍历 for (int j = i + 1; j < len; j++) { // 如果区间右端点小于新区间右端点,会被合并后的区间覆盖 if (intervals[j][1] < newInterval[1]) intervals.erase(intervals.begin() + j); if (newInterval[1] <= intervals[j][1] && newInterval[1] >= intervals[j][0]) { // 右端点落在了某个区间中(相等的情况没有被删除) intervals[j][0] = newInterval[0]; break; } // 右端点也没有落在任何区间 if (j == len - 1) intervals.push_back(newInterval); } break; } } return intervals; } };
这一版的代码犯了很大一个错误——我不能一遍遍历数组一遍删除数组(好吧我还尝试了知错不改邪魔外道尝试去修改指针)
其实就想剩下额外的空间,不想再准备一个二维数组去存放结果
class Solution { public: vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) { int len = intervals.size(); if (!len) return { newInterval }; vector<vector<int>>res; // 首先确定左端点是否落在了某个区间中 for (int i = 0; i < len; i++) { if (intervals[i][1] >= newInterval[0] && intervals[i][0] <= newInterval[0]) { // 新区间的左端点落在某个区间中 // 不管右端点怎么样,新区间的左端点都会被合并 // 然后去找右端点 for (int j = i; j < len; j++) { if (intervals[j][0] > newInterval[1] || j == len - 1) { // 右端点不在任何一个区间内 res.back()[1] = newInterval[1]; res.push_back(intervals[j]); break; } if (newInterval[1] <= intervals[j][1] || intervals[j][0] <= newInterval[1]) { // 右端点落在了某个区间中 intervals[i][1] = intervals[j][1];// 合并新区间 res.push_back(intervals[i]); } } break; } else if (intervals[i][0] > newInterval[0]) { // 说明确定了左端点没有落在任何一个区间中 // 判断确定了第一个大于左端点的区间,因为右端点一定大于左端点,所以可以接着遍历 for (int j = i; j < len; j++) { if (newInterval[1] <= intervals[j][1] && intervals[j][0] <= newInterval[1]) { // 右端点落在了某个区间中(相等的情况没有被删除) intervals[j][0] = newInterval[0]; res.push_back(intervals[j]); } if (intervals[j][0] > newInterval[1]) res.push_back(intervals[j]); else if (j == len - 1)(res.back()[1] = newInterval[1]); } break; } else { // 首先左端点没有在任何一个区间,其次左端点不在区间左边,左端点在区间右边 res.push_back(intervals[i]); } } return res; } };
昨天尝试未果,沿用上面的思路其实具体实现起来仍旧是老路子,比如:遍历确定左端点位置就要分四种情况:
- 左端点在所有区间前面
- 左端点在中间,但是没有落在任何一个区间中
- 左端点在中间且落在了某个区间中
- 左端点在所有区间后面
这样写需要在遍历中嵌套两个相似的遍历,同时还要两个端点各分四种情况,还有取不取等的情况,过于繁琐细致了
官解给出的方法是排序
官解排序
官方题解思路的出发点是:按照所有区间的左端点排序,能够合并的区间一定是连续的
怎么证明暂且不研究,排序然后呢?然后遍历排序后的数组,看能不能合并
class Solution { public: vector<vector<int>> insert(vector<vector<int>>& intervals, vector<int>& newInterval) { // 官方题解思路的出发点是:按照所有区间的左端点排序,能够合并的区间一定是连续的 // 因为只有一个插入数组,所以其实不用真的排一轮 // 好吧,排一轮也可以 int len = intervals.size(); if (!len) return { newInterval };// 如果原二维数组空,直接返回新区间 vector<vector<int>> res; intervals.push_back(newInterval); sort(intervals.begin(), intervals.end()); // 比较两个区间能不能合并(感觉有点冒泡两两比较的味儿了) for (int i = 1; i < len+1; i++) { // 有几种情况? // 1. 不能合并,两个独立的区间 // 2. 可以部分合并,就是相交 // 3. 包含 if (intervals[i - 1][1] > intervals[i][1]) { // 包含 intervals[i][0] = intervals[i - 1][0]; intervals[i][1] = intervals[i - 1][1]; } else { if (intervals[i - 1][1] >= intervals[i][0]) { // 相交 intervals[i][0] = intervals[i - 1][0]; } else { // 不相关 res.push_back(intervals[i - 1]); } } } res.push_back(intervals.back());// 清空,处理最后一个 return res; } };
看看能不能优化一下
如果哪里可以优化应该优化我觉得时间会是去掉排序,空间是直接用原数组😂然后看起来又是最开始的老路子
就这样吧,溜了溜了
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/17070308.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步