编程-线段树
729. 我的日程安排表 I
实现一个
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:
MyCalendar(); MyCalendar.book(10, 20); // returns true MyCalendar.book(15, 25); // returns false MyCalendar.book(20, 30); // returns true 解释: 第一个日程安排可以添加到日历中. 第二个日程安排不能添加到日历中,因为时间 15 已经被第一个日程安排预定了。 第三个日程安排可以添加到日历中,因为第一个日程安排并不包含时间 20 。
说明:
- 每个测试用例,调用
MyCalendar.book函数最多不超过1000次。 - 调用函数
MyCalendar.book(start, end)时,start和end的取值范围为[0, 10^9]。
解法1:
typedef struct tag_time_zone { int start; int end; tag_time_zone(int i1, int i2) { start = i1; end = i2; } } time_zone; class MyCalendar { public: vector<time_zone> vec1; bool book(int start, int end) { for (vector<time_zone>::iterator it1 = vec1.begin(); it1 != vec1.end(); ++it1) { if (start >= it1->start && start < it1->end) { return false; } else if (end > it1->start && end <= it1->end) { return false; } else if (start <= it1->start && end > it1->end) { return false; } } vec1.push_back(time_zone(start,end)); return true; } }; /** * Your MyCalendar object will be instantiated and called as such: * MyCalendar* obj = new MyCalendar(); * bool param_1 = obj->book(start,end); */ int main() { MyCalendar myCalendar; vector<vector<int>> shuchu = {{97,100},{33,51},{89,100},{83,100},{75,92},{76,95},{19,30},{53,63},{8,23},{18,37},{87,100},{83,100},{54,67},{35,48},{58,75},{70,89},{13,32},{44,63},{51,62},{2,15}}; for (int i = 0; i < shuchu.size(); ++i) { cout<<myCalendar.book(shuchu[i][0], shuchu[i][1]); // returns true } cout<<endl; for(auto c : myCalendar.vec1) { cout << c.start << " " << c.end <<endl; } return 0; }
解法2:
class MyCalendar { public: map<int, int> map1; bool book(int start, int end) { //for (map<int, int>::iterator it1 = map1.begin(); it1 != map1.end(); ++it1) { for (auto &c : map1) { if (start >= c.first && start < c.second) { return false; } else if (end > c.first && end <= c.second) { return false; } else if (start <= c.first && end > c.second) { return false; } } map1.insert(make_pair(start, end)); return true; } };
307. 区域和检索 - 数组可修改
给你一个数组
nums ,请你完成两类查询,其中一类查询要求更新数组下标对应的值,另一类查询要求返回数组中某个范围内元素的总和。实现 NumArray 类:
NumArray(int[] nums)用整数数组nums初始化对象void update(int index, int val)将nums[index]的值更新为valint sumRange(int left, int right)返回子数组nums[left, right]的总和(即,nums[left] + nums[left + 1], ..., nums[right])
示例:
输入: ["NumArray", "sumRange", "update", "sumRange"] [[[1, 3, 5]], [0, 2], [1, 2], [0, 2]] 输出: [null, 9, null, 8] 解释: NumArray numArray = new NumArray([1, 3, 5]); numArray.sumRange(0, 2); // 返回 9 ,sum([1,3,5]) = 9 numArray.update(1, 2); // nums = [1,2,5] numArray.sumRange(0, 2); // 返回 8 ,sum([1,2,5]) = 8
提示:
1 <= nums.length <= 3 * 104-100 <= nums[i] <= 1000 <= index < nums.length-100 <= val <= 1000 <= left <= right < nums.length- 最多调用
3 * 104次update和sumRange方法
线段树是一种非常灵活的数据结构,它可以用于解决多种范围查询问题,比如在对数时间内从数组中找到最小值、最大值、总和、最大公约数、最小公倍数等。
解法1: c构造线段树类
class SegTree { public: vector<int> nums; vector<int> treesum; int n; SegTree(vector<int> nums) { this->nums = nums; this->n = nums.size(); treesum.resize(4 * n, 0); if (n > 0) _build(0, 0, n - 1); } void _build(int root, int l, int r) { if (l == r) { treesum[root] = nums[r]; return; } int left = 2 * root + 1; int right = 2 * root + 2; int mid = (l + r) >> 1; _build(left, l, mid); _build(right, mid + 1, r); treesum[root] = treesum[left] + treesum[right]; } void update(int ID, int newValue) { _update(0, 0, n - 1, ID, newValue); } void _update(int root, int l, int r, int ID, int newValue) { if (l == ID && r == ID) { treesum[root] = newValue; return; } int left = 2 * root + 1; int right = 2 * root + 2; int mid = (l + r) >> 1; if (ID <= mid) _update(left, l, mid, ID, newValue); else _update(right, mid + 1, r, ID, newValue); treesum[root] = treesum[left] + treesum[right]; } int query(int ql, int qr) { return _query(0, 0, n - 1, ql, qr); } int _query(int root, int l, int r, int ql, int qr) { if (l == ql && r == qr) return treesum[root]; int left = 2 * root + 1; int right = 2 * root + 2; int mid = (l + r) >> 1; if (qr <= mid) return _query(left, l, mid, ql, qr); else if (mid + 1 <= ql) return _query(right, mid + 1, r, ql, qr); return _query(left, l, mid, ql, mid) + _query(right, mid + 1, r, mid + 1, qr); } }; class NumArray { public: SegTree * ST; NumArray(vector<int>& nums) { ST = new SegTree(nums); } void update(int index, int val) { ST->update(index, val); } int sumRange(int left, int right) { return ST->query(left, right); } }; /** * Your NumArray object will be instantiated and called as such: * NumArray* obj = new NumArray(nums); * obj->update(index,val); * int param_2 = obj->sumRange(left,right); */
c++线段树简易版
class NumArray { public: vector<int> tree; int n; NumArray(vector<int> &nums) { if (nums.size() > 0) { n = nums.size(); tree.resize(n * 2); buildTree(nums); } } void buildTree(vector<int> &nums) { for (int i = n, j = 0; i < 2 * n; i++, j++) tree[i] = nums[j]; for (int i = n - 1; i > 0; --i) tree[i] = tree[i * 2] + tree[i * 2 + 1]; } void update(int pos, int val) { pos += n; tree[pos] = val; while (pos > 0) { int left = pos; int right = pos; if (pos % 2 == 0) { right = pos + 1; } else { left = pos - 1; } // parent is updated after child is updated tree[pos / 2] = tree[left] + tree[right]; pos /= 2; } } int sumRange(int l, int r) { // get leaf with value 'l' l += n; // get leaf with value 'r' r += n; int sum = 0; while (l <= r) { if ((l % 2) == 1) { sum += tree[l]; l++; } if ((r % 2) == 0) { sum += tree[r]; r--; } l /= 2; r /= 2; } return sum; } };

浙公网安备 33010602011771号