力扣-57-插入区间

采用最直接的思路,if-else去考虑每一种情况并做出操作(比如找到新区间左端点落在哪个位置,几种情况,然后再去考虑右端点的几种情况)是非常细致繁琐的,以至于很容易出错

考虑三种情况,新区间的两个端点:

  1. 分别落在两个原有的区间中:保留前一个区间的左端点和后一个区间的右端点,将他俩合并成一个新的区间
  2. 只有一个端点落在了某个区间:以左端点落在了某个区间为例,就将区间左端点和新区间的右端点合并为一个区间
  3. 两个端点没有落在任何区间:直接插入作为新的区间成员

另外需要考虑到的是:以上合并的情况中,所有被新合并区间所包含的区间全部都需要删除

编码

  1. 我需要知道这两个端点有没有落在区间中,如果有,做右端点又分别是谁

需要额外仔细考虑的是各个等于的情况

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;
	}
};

昨天尝试未果,沿用上面的思路其实具体实现起来仍旧是老路子,比如:遍历确定左端点位置就要分四种情况:

  1. 左端点在所有区间前面
  2. 左端点在中间,但是没有落在任何一个区间中
  3. 左端点在中间且落在了某个区间中
  4. 左端点在所有区间后面

这样写需要在遍历中嵌套两个相似的遍历,同时还要两个端点各分四种情况,还有取不取等的情况,过于繁琐细致了

官解给出的方法是排序

官解排序

官方题解思路的出发点是:按照所有区间的左端点排序,能够合并的区间一定是连续的

怎么证明暂且不研究,排序然后呢?然后遍历排序后的数组,看能不能合并

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;
	}
};

看看能不能优化一下
如果哪里可以优化应该优化我觉得时间会是去掉排序,空间是直接用原数组😂然后看起来又是最开始的老路子
就这样吧,溜了溜了

posted @ 2023-01-29 10:40  YaosGHC  阅读(30)  评论(0)    收藏  举报