class Time {
public:
int start;
int end;
Time(int s, int e) :start(s), end(e) {}
};//定义时间区间
按end时间排序
最多不重叠区间数
bool cmp(const Time& t1, const Time& t2) {
return t1.end < t2.end;
}
int countNoOverlap(const vector<int>& vstart, const vector<int>& vend) {
if (vstart.size() != vend.size() || vstart.empty()) return -1;
vector<Time> vtime;
for (int i = 0; i < vstart.size(); ++i)
vtime.push_back(Time(vstart[i], vend[i]));
sort(vtime.begin(), vtime.end(),cmp);
int amount = 0, prevEnd = 0;
for (int i = 0; i < vtime.size(); ++i) {
if (prevEnd < vtime[i].start) {
amount++;
prevEnd = vtime[i].end;
}
}
return amount;
}
最长不重叠区间和
现在有n个工作要完成,每项工作分别在 时间开始,在 时间结束。对于每项工作,你都可以选择参与与否。如果选择了参与,那么自始至终都必须全程参与。此外,参与工作的时间段不能重叠(闭区间)。求你参与的所有工作最大需要耗费多少时间,另一种说法是:想投入最多时间到工作中,求这个最长时间。 这里动态规划就能很好地求解。
int noOverlap(const vector<Time>& vtime, int pos, const Time& t) {
for (int i = pos; i >=0; --i)
if (vtime[i].end < t.start)
return i;
return -1;
}
int longestNoOverlap(const vector<int>& vstart, const vector<int>& vend) {
if (vstart.size() != vend.size() || vstart.empty()) return -1;
vector<Time> vtime;
for (int i = 0; i < vstart.size(); ++i)
vtime.push_back(Time(vstart[i], vend[i]));
sort(vtime.begin(), vtime.end(), cmp);
//DP
int* dp = new int[vtime.size()];
dp[0] = vtime[0].end - vtime[0].start;
int longest = dp[0];
for (int i = 1; i < vtime.size(); ++i) {
if (int pos = noOverlap(vtime, i, vtime[i]) >= 0)
longest = dp[pos] + vtime[i].end - vtime[i].start;
else
longest = vtime[i].end - vtime[i].start;
dp[i] = max(dp[i - 1], longest);
}
delete[]dp;
return dp[vtime.size()-1];
}
带权区间调度(选取价值最大的区间集)
typedef struct Node {
int start;
int end;
int value;
Node(int s, int e, int v) :start(s), end(e), value(v) {}
long long getValue() {
return value*(end - start);
}
} node;
bool cmpNd(const Node& n1, const Node& n2) {
return n1.end < n2.end;
}
int findNoOverlap(const vector<Node>& wTime, int pos, const Node& node) {
for (int i = pos; i >= 0; --i)
if (wTime[i].end < node.start)
return i;
return -1;
}
int bestValueNoOverlap(const vector<int>& vstart, const vector<int>& vend, const vector<int>& weight) {
//防御式编程,检查入参的合法性
//...
vector<node> wTime;
for (int i = 0; i < vstart.size(); ++i)
wTime.push_back(Node(vstart[i], vend[i], weight[i]));
sort(wTime.begin(), wTime.end(), cmpNd);
//DP
long long* dp = new long long[vstart.size()];
dp[0] = wTime[0].getValue();
long long best = 0;
for (int i = 1; i < wTime.size(); ++i) {
int pos = findNoOverlap(wTime, i, wTime[i]);
if (pos >= 0)
best = dp[pos] + wTime[i].getValue();
else
best = wTime[i].getValue();
dp[i] = max(best, dp[i - 1]);
}
delete[]dp;
return dp[wTime.size() - 1];
}
按start时间排序
覆盖指定区域所需的最少区间数
bool cmp2(const Time& t1, const Time& t2) {
return t1.start < t2.start;
}
int leastRangeToOverlap(vector<Time>& vtime, const int left, const int right,vector<Time>& range) {
if (vtime.empty() || left >= right) return -1;
sort(vtime.begin(), vtime.end(), cmp2);
int n = vtime.size();
int i = 0;
int tleft = left;
int max_right = 0;
int pos;
int amount = 0;
while (i<n)
{
while (vtime[i].start <= tleft) {
if (vtime[i].end > max_right) {
max_right = vtime[i].end;
pos = i;
}
++i;
}
if (max_right > tleft) {
range.push_back(vtime[pos]);
amount++;
tleft = max_right;
if (tleft >= right)
return amount;
++i;
}
else
return -1;
}
return amount;
}
区间的最长重叠部分
//先start排序,从左往右扫描,从相邻的区间找出最大的重叠部分
会议房间最佳安排(所用的房间最少)
typedef struct Meet {
int num;
int time;//开始或结束时间
int sore;//开始为1,结束为0
int room = -1;
Meet(int n, int t, int f) :num(n), time(t), sore(f) {}
};
bool cmp3(const Meet& m1, const Meet& m2) {
if (m1.time == m2.time) return m1.sore < m2.sore;
return m1.time < m2.time;
}
class MeetSchedule {
public:
int meetingRoomSchedule(const vector<int>& vstart, const vector<int>& vend, vector<vector<int>>& vret) {
//防御式编程
vector<Meet> vtime;
for (int i = 0; i < vstart.size(); ++i) {
vtime.push_back(Meet(i, vstart[i], 1));
vtime.push_back(Meet(i, vend[i], 0));
}
sort(vtime.begin(), vtime.end(), cmp3);
stack<int> stkroom; //准备教室
for (int i = vstart.size(); i >= 1; --i)
stkroom.push(i);
int maxNum = 0;
for (int i = 0; i < vtime.size() - 1; ++i) {
if (vtime[i].sore) {
maxNum = max(maxNum, stkroom.top());
vtime[i].room = stkroom.top();
stkroom.pop();
setEndRoom(vtime, i, vtime[i]);
vret.push_back(vector<int>{vtime[i].num, vtime[i].room});
}
else
stkroom.push(vtime[i].room);
}
return maxNum;
}
private:
void setEndRoom(vector<Meet>& vtime, int pos, Meet& node) {
for (int i = pos + 1; i < vtime.size(); ++i)
if (vtime[i].num == node.num)
vtime[i].room = node.room;
}
};
leetcode 三题
435无重叠区间(低频)
给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。
注意:
可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/non-overlapping-intervals 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
public int eraseOverlapIntervals(int[][] intervals) {
if (intervals.length == 0)
return 0;
//先排序
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
//记录区间尾部的位置
int end = intervals[0][1];
//需要移除的数量
int count = 0;
for (int i = 1; i < intervals.length; i++) {
if (intervals[i][0] < end) {
//如果重叠了,必须要移除一个,所以count要加1,
//两个区间有重复,必须要移除一个,那么要移除哪个呢,为了防止在下一个区间和现有区间有重叠,我们应该让现有区间越短越好,所以应该移除尾部比较大的,保留尾部比较小的。
end = Math.min(end, intervals[i][1]);
count++;
} else {
//如果没有重叠,就不需要移除,只需要更新尾部的位置即可
end = intervals[i][1];
}
}
return count;
}
986区间列表的交集(低频)
给定两个由一些 闭区间 组成的列表,每个区间列表都是成对不相交的,并且已经排序。返回这两个区间列表的交集。
(形式上,闭区间 [a, b](其中 a <= b)表示实数 x 的集合,而 a <= x <= b。两个闭区间的交集是一组实数,要么为空集,要么为闭区间。例如,[1, 3] 和 [2, 4] 的交集为 [2, 3]。)
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/interval-list-intersections 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
题目说,给定的两个区间列表都是排好序的
用两个指针,分别扫描 A、B 数组,根据子区间的左右端,求出一个交集区间
指针移动,直至指针越界,得到由交集区间组成的数组。
const intervalIntersection = (A, B) => {
const res = [];
let i = 0;
let j = 0;
while (i < A.length && j < B.length) {
const start = Math.max(A[i][0], B[j][0]); // 交集区间的左端,取它们的较大者
const end = Math.min(A[i][1], B[j][1]); // 交集区间的右端,取它们的较小者
if (start <= end) { // 形成了交集区间
res.push([start, end]);
}
if (A[i][1] < B[j][1]) { // 谁先结束,谁的指针就步进,考察下一个子区间
i++;
} else {
j++;
}
}
return res;
};
作者:xiao_ben_zhu
链接:https://leetcode-cn.com/problems/interval-list-intersections/solution/jiu-pa-ni-bu-dong-shuang-zhi-zhen-by-hyj8/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
56合并区间(中频)
给出一个区间的集合,请合并所有重叠的区间。
//很容易,贪心做法就行。
sort(arr.begin(),arr.end(),[]->{a.start<b.start});
curL=arr[0].start;curR=arr[0].end;
for(int i=1;i<arr.size();++i){
if(arr[i].start<=curR){
curR=max(arr[i].end,curR);
}else{
ret.add(pair<int,int>(curL,curR));
curL=arr[i].start;
curR=arr[i].end;
}
}
return ret;