mirror of
https://github.com/halfrost/LeetCode-Go.git
synced 2025-07-04 16:12:47 +08:00
添加 problem 715
This commit is contained in:
203
Algorithms/0715. Range Module/715. Range Module.go
Normal file
203
Algorithms/0715. Range Module/715. Range Module.go
Normal file
@ -0,0 +1,203 @@
|
||||
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);
|
||||
*/
|
36
Algorithms/0715. Range Module/715. Range Module_test.go
Normal file
36
Algorithms/0715. Range Module/715. Range Module_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package leetcode
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_Problem715(t *testing.T) {
|
||||
obj := Constructor715()
|
||||
obj.AddRange(10, 20)
|
||||
obj.RemoveRange(14, 16)
|
||||
fmt.Printf("query = %v\n", obj.QueryRange(10, 14)) // returns true
|
||||
fmt.Printf("query = %v\n", obj.QueryRange(13, 15)) // returns false
|
||||
fmt.Printf("query = %v\n\n", obj.QueryRange(16, 17)) // returns true
|
||||
|
||||
obj1 := Constructor715()
|
||||
obj1.AddRange(10, 180)
|
||||
obj1.AddRange(150, 200)
|
||||
obj1.AddRange(250, 500)
|
||||
fmt.Printf("query = %v\n", obj1.QueryRange(50, 100)) // returns true
|
||||
fmt.Printf("query = %v\n", obj1.QueryRange(180, 300)) // returns false
|
||||
fmt.Printf("query = %v\n", obj1.QueryRange(600, 1000)) // returns false
|
||||
obj1.RemoveRange(50, 150)
|
||||
fmt.Printf("query = %v\n\n", obj1.QueryRange(50, 100)) // returns false
|
||||
|
||||
obj2 := Constructor715()
|
||||
obj2.AddRange(6, 8)
|
||||
obj2.RemoveRange(7, 8)
|
||||
obj2.RemoveRange(8, 9)
|
||||
obj2.AddRange(8, 9)
|
||||
obj2.RemoveRange(1, 3)
|
||||
obj2.AddRange(1, 8)
|
||||
fmt.Printf("query = %v\n", obj2.QueryRange(2, 4)) // returns true
|
||||
fmt.Printf("query = %v\n", obj2.QueryRange(2, 9)) // returns true
|
||||
fmt.Printf("query = %v\n", obj2.QueryRange(4, 6)) // returns true
|
||||
}
|
60
Algorithms/0715. Range Module/README.md
Executable file
60
Algorithms/0715. Range Module/README.md
Executable file
@ -0,0 +1,60 @@
|
||||
# [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 题的俄罗斯方块的方块会“断裂”。
|
Reference in New Issue
Block a user