Files
LeetCode-Go/website/content/ChapterFour/0715.Range-Module.md
2020-08-09 00:39:24 +08:00

270 lines
9.3 KiB
Markdown
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# [715. Range Module](https://leetcode.com/problems/range-module/)
## 题目
A Range Module is a module that tracks ranges of numbers. Your task is to design and implement the following interfaces in an efficient manner.
- `addRange(int left, int right)` Adds the half-open interval `[left, right)`, tracking every real number in that interval. Adding an interval that partially overlaps with currently tracked numbers should add any numbers in the interval `[left, right)` that are not already tracked.
- `queryRange(int left, int right)` Returns true if and only if every real number in the interval `[left, right)` is currently being tracked.
- `removeRange(int left, int right)` Stops tracking every real number currently being tracked in the interval `[left, right)`.
**Example 1**:
addRange(10, 20): null
removeRange(14, 16): null
queryRange(10, 14): true (Every number in [10, 14) is being tracked)
queryRange(13, 15): false (Numbers like 14, 14.03, 14.17 in [13, 15) are not being tracked)
queryRange(16, 17): true (The number 16 in [16, 17) is still being tracked, despite the remove operation)
**Note**:
- A half open interval `[left, right)` denotes all real numbers `left <= x < right`.
- `0 < left < right < 10^9` in all calls to `addRange, queryRange, removeRange`.
- The total number of calls to `addRange` in a single test case is at most `1000`.
- The total number of calls to `queryRange` in a single test case is at most `5000`.
- The total number of calls to `removeRange` in a single test case is at most `1000`.
## 题目大意
Range 模块是跟踪数字范围的模块。你的任务是以一种有效的方式设计和实现以下接口。
- addRange(int left, int right) 添加半开区间 [left, right),跟踪该区间中的每个实数。添加与当前跟踪的数字部分重叠的区间时,应当添加在区间 [left, right) 中尚未跟踪的任何数字到该区间中。
- queryRange(int left, int right) 只有在当前正在跟踪区间 [left, right) 中的每一个实数时,才返回 true。
- removeRange(int left, int right) 停止跟踪区间 [left, right) 中当前正在跟踪的每个实数。
 
示例:
```
addRange(10, 20): null
removeRange(14, 16): null
queryRange(10, 14): true (区间 [10, 14) 中的每个数都正在被跟踪)
queryRange(13, 15): false (未跟踪区间 [13, 15) 中像 14, 14.03, 14.17 这样的数字)
queryRange(16, 17): true (尽管执行了删除操作,区间 [16, 17) 中的数字 16 仍然会被跟踪)
```
提示:
- 半开区间 [left, right) 表示所有满足 left <= x < right 的实数
-  addRange, queryRange, removeRange 的所有调用中 0 < left < right < 10^9
- 在单个测试用例中 addRange 的调用总数不超过 1000 
- 在单个测试用例中  queryRange 的调用总数不超过 5000
- 在单个测试用例中 removeRange 的调用总数不超过 1000 
## 解题思路
- 设计一个数据结构能完成添加区间 `addRange`查询区间 `queryRange`移除区间 `removeRange` 三种操作查询区间的操作需要更加高效一点
- 这一题可以用线段树来解答但是时间复杂度不高最优解是用二叉排序树 BST 来解答先来看线段树这一题是更新区间内的值所以需要用到懒惰更新添加区间可以把区间内的值都赋值为 1 由于题目中未预先确定区间范围选用树的形式实现线段树比数组实现更加节约空间(当然用数组也可以区间最大是 1000点至多有 2000 )。移除区间的时候就是把区间内的值都赋值标记为 0
- 类似的题目有 699 218 732 715 题是区间更新定值(**不是增减**) 218 题可以用扫描线 732 题和第 699 题类似也是俄罗斯方块的题目但是第 732 题的俄罗斯方块的方块会断裂”。
## 代码
```go
package leetcode
// RangeModule define
type RangeModule struct {
Root *SegmentTreeNode
}
// SegmentTreeNode define
type SegmentTreeNode struct {
Start, End int
Tracked bool
Lazy int
Left, Right *SegmentTreeNode
}
// Constructor715 define
func Constructor715() RangeModule {
return RangeModule{&SegmentTreeNode{0, 1e9, false, 0, nil, nil}}
}
// AddRange define
func (rm *RangeModule) AddRange(left int, right int) {
update(rm.Root, left, right-1, true)
}
// QueryRange define
func (rm *RangeModule) QueryRange(left int, right int) bool {
return query(rm.Root, left, right-1)
}
// RemoveRange define
func (rm *RangeModule) RemoveRange(left int, right int) {
update(rm.Root, left, right-1, false)
}
func lazyUpdate(node *SegmentTreeNode) {
if node.Lazy != 0 {
node.Tracked = node.Lazy == 2
}
if node.Start != node.End {
if node.Left == nil || node.Right == nil {
m := node.Start + (node.End-node.Start)/2
node.Left = &SegmentTreeNode{node.Start, m, node.Tracked, 0, nil, nil}
node.Right = &SegmentTreeNode{m + 1, node.End, node.Tracked, 0, nil, nil}
} else if node.Lazy != 0 {
node.Left.Lazy = node.Lazy
node.Right.Lazy = node.Lazy
}
}
node.Lazy = 0
}
func update(node *SegmentTreeNode, start, end int, track bool) {
lazyUpdate(node)
if start > end || node == nil || end < node.Start || node.End < start {
return
}
if start <= node.Start && node.End <= end {
// segment completely covered by the update range
node.Tracked = track
if node.Start != node.End {
if track {
node.Left.Lazy = 2
node.Right.Lazy = 2
} else {
node.Left.Lazy = 1
node.Right.Lazy = 1
}
}
return
}
update(node.Left, start, end, track)
update(node.Right, start, end, track)
node.Tracked = node.Left.Tracked && node.Right.Tracked
}
func query(node *SegmentTreeNode, start, end int) bool {
lazyUpdate(node)
if start > end || node == nil || end < node.Start || node.End < start {
return true
}
if start <= node.Start && node.End <= end {
// segment completely covered by the update range
return node.Tracked
}
return query(node.Left, start, end) && query(node.Right, start, end)
}
// 解法二 BST
// type RangeModule struct {
// Root *BSTNode
// }
// type BSTNode struct {
// Interval []int
// Left, Right *BSTNode
// }
// func Constructor715() RangeModule {
// return RangeModule{}
// }
// func (this *RangeModule) AddRange(left int, right int) {
// interval := []int{left, right - 1}
// this.Root = insert(this.Root, interval)
// }
// func (this *RangeModule) RemoveRange(left int, right int) {
// interval := []int{left, right - 1}
// this.Root = delete(this.Root, interval)
// }
// func (this *RangeModule) QueryRange(left int, right int) bool {
// return query(this.Root, []int{left, right - 1})
// }
// func (this *RangeModule) insert(root *BSTNode, interval []int) *BSTNode {
// if root == nil {
// return &BSTNode{interval, nil, nil}
// }
// if root.Interval[0] <= interval[0] && interval[1] <= root.Interval[1] {
// return root
// }
// if interval[0] < root.Interval[0] {
// root.Left = insert(root.Left, []int{interval[0], min(interval[1], root.Interval[0]-1)})
// }
// if root.Interval[1] < interval[1] {
// root.Right = insert(root.Right, []int{max(interval[0], root.Interval[1]+1), interval[1]})
// }
// return root
// }
// func (this *RangeModule) delete(root *BSTNode, interval []int) *BSTNode {
// if root == nil {
// return nil
// }
// if interval[0] < root.Interval[0] {
// root.Left = delete(root.Left, []int{interval[0], min(interval[1], root.Interval[0]-1)})
// }
// if root.Interval[1] < interval[1] {
// root.Right = delete(root.Right, []int{max(interval[0], root.Interval[1]+1), interval[1]})
// }
// if interval[1] < root.Interval[0] || root.Interval[1] < interval[0] {
// return root
// }
// if interval[0] <= root.Interval[0] && root.Interval[1] <= interval[1] {
// if root.Left == nil {
// return root.Right
// } else if root.Right == nil {
// return root.Left
// } else {
// pred := root.Left
// for pred.Right != nil {
// pred = pred.Right
// }
// root.Interval = pred.Interval
// root.Left = delete(root.Left, pred.Interval)
// return root
// }
// }
// if root.Interval[0] < interval[0] && interval[1] < root.Interval[1] {
// left := &BSTNode{[]int{root.Interval[0], interval[0] - 1}, root.Left, nil}
// right := &BSTNode{[]int{interval[1] + 1, root.Interval[1]}, nil, root.Right}
// left.Right = right
// return left
// }
// if interval[0] <= root.Interval[0] {
// root.Interval[0] = interval[1] + 1
// }
// if root.Interval[1] <= interval[1] {
// root.Interval[1] = interval[0] - 1
// }
// return root
// }
// func (this *RangeModule) query(root *BSTNode, interval []int) bool {
// if root == nil {
// return false
// }
// if interval[1] < root.Interval[0] {
// return query(root.Left, interval)
// }
// if root.Interval[1] < interval[0] {
// return query(root.Right, interval)
// }
// left := true
// if interval[0] < root.Interval[0] {
// left = query(root.Left, []int{interval[0], root.Interval[0] - 1})
// }
// right := true
// if root.Interval[1] < interval[1] {
// right = query(root.Right, []int{root.Interval[1] + 1, interval[1]})
// }
// return left && right
// }
/**
* Your RangeModule object will be instantiated and called as such:
* obj := Constructor();
* obj.AddRange(left,right);
* param_2 := obj.QueryRange(left,right);
* obj.RemoveRange(left,right);
*/
```