LeetCode 1851. 包含每个查询的最小区间

题目链接:包含每个查询的最小区间

 

题解:偏序+离线模板题,单点修改区间查询(我这里用的是树状数组)
        1. 先把区间数组按左端点从小到大排序,询问数组也从小到大排序

        2. 对于每一个询问k,先将所有左端点小于等于queries[k]的区间维护到树状数组上——以右端点为下标,区间长度为权值;再查询所有包含queries[k]的区间的最小长度,即区间查询树状数组[queries[k],MAXSIZE)的最小值。对于后续的询问,因为权值是递增的,所以之前所维护的区间的左端均小于询问的权值,重复上述操作即可

        3. 如果不好理解,可以将区间和询问均想象成二维平面上的点,如下图所示:


        low表示区间左端点,high表示区间右端点,high轴相当于我们所维护的树状数组
        黑色的点表示维护的区间,红色点表示询问,对于2这个询问,我们只需要区间查询绿色框中所有区间的最小长度

        4. 区间端点的值域太大,需要先进行离散化

代码示例:

class Solution {
public:

#define INF				std::numeric_limits<int>::max()

	vector<int> discrete;
	vector<int> bitree, origin;
	vector<pair<int, int>> que;
	int n, m, sz;

	int Idx(int x) {
		return lower_bound(discrete.begin(), discrete.end(), x) - discrete.begin();
	}

	int Lowbit(int x) {
		return x & -x;
	}

	void Modify(int x, int val) {
		origin[x] = min(origin[x], val);
		while (x < sz) {
			bitree[x] = min(bitree[x], val);
			x += Lowbit(x);
		}
	}

	int Query(int l, int r) {
		int res = INF;
		while (r >= l) {
			if (r - Lowbit(r) >= l) {
				res = min(res, bitree[r]);
				r -= Lowbit(r);
			}
			else {
				res = min(res, origin[r]);
				--r;
			}
		}
		return res == INF ? -1 : res;
	}

	vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries) {
		sort(intervals.begin(), intervals.end(), [](vector<int>& a, vector<int>& b)->bool { return a[0] < b[0]; });
		n = intervals.size();
		m = queries.size();

		que.resize(m);
		for (int i = 0; i < m; ++i) que[i] = pair<int, int>{ queries[i], i };
		sort(que.begin(), que.end());

		sz = n * 2 + m;
		discrete.reserve(sz);
		discrete.push_back(-1);
		for (auto& i : intervals) {
			discrete.push_back(i[0]);
			discrete.push_back(i[1]);
		}
		for (auto i : queries) discrete.push_back(i);
		sort(discrete.begin(), discrete.end());
		discrete.erase(unique(discrete.begin(), discrete.end()), discrete.end());
		sz = discrete.size();
		bitree.resize(sz, INF);
		origin.resize(sz, INF);

		vector<int> res(m);
		int i = 0, j = 0;
		while (j < m) {
			while (i < n && intervals[i][0] <= que[j].first) {
				auto& pr = intervals[i];
				Modify(Idx(pr[1]), pr[1] - pr[0] + 1);
				++i;
			}
			res[que[j].second] = Query(Idx(que[j].first), sz - 1);
			++j;
		}
		return res;
	}
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IN0vation

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值