set-intersection-size-at-least-two
| 属性 | 内容 |
|---|---|
| 难度 | hard |
| 标签 | sorting, greedy, segment-tree |
| 链接 | 在线题目 |
| 评分 | 8 |
| 创建时间 | 2025-11-20 11:59:25 |
| 更新时间 | 2025-11-20 12:01:55 |
📖 题目描述
暂无题目描述
💡 解题思路
主要是学习动态开点线段树怎么写,自顶向下查询即可. 如果查询区间包含了当前node的l和r则直接返回数据,否则二分之后继续递归查询。
更新也是一样的逻辑,如果当前区间已经包含了当前的l和r则直接更新当前区间即可。
注意有一个懒更新的思想,每一个node节点都有一个lazy标记,查询和更新操作下一层子节点之前,需要判断当前node是否有lazy标记,如有,需要及时更新子节点的值,再去做查询和更新操作
🛠 代码实现
go
package leetcode
import (
"math"
"sort"
)
func intersectionSizeTwo(intervals [][]int) int {
sort.Slice(intervals, func(i, j int) bool {
return intervals[i][1] < intervals[j][1]
})
// 排序之后 数组为 [1, 4] [2, 5] [6, 7]这种类似的 可以看出来 优先选择
mx := 0
mn := math.MaxInt32
for i := 0; i < len(intervals); i++ {
intervals[i] = append(intervals[i], 2)
mx = max(mx, intervals[i][1])
mn = min(mn, intervals[i][0])
}
tree := NewSegmentTree(mn, mx, &SegmentTreeOption[int]{MergeVal: func(a, b int) int {
return a + b
}, InitVal: func() int {
return 0
}, UpdateNode: func(val int, left, right int) int {
return (right - left + 1) * val
},
})
// 贪心思想 每一个区间判断当前有多少个已经存在的数字 是否还需要添加 如需要添加从最尾端开始尝试添加即可
// 正对查询一个区间已存在多少数字的逻辑 可以通过线段树来做
ans := 0
vis := make(map[int]interface{})
for i := 0; i < len(intervals); i++ {
cnt := tree.Query(intervals[i][0], intervals[i][1])
if cnt < intervals[i][2] {
temp := intervals[i][2] - cnt
for j := intervals[i][1]; j >= intervals[i][0]; j-- {
if _, ok := vis[j]; ok {
continue
}
vis[j] = struct{}{}
temp--
ans++
tree.Update(j, j, 1)
if temp == 0 {
break
}
}
}
}
return ans
}
type SegmentTree[T any] struct {
root *segmentTreeNode[T]
options *SegmentTreeOption[T]
}
type SegmentTreeOption[T any] struct {
MergeVal func(a, b T) T
UpdateNode func(val T, left, right int) T
InitVal func() T
}
type segmentTreeNode[T any] struct {
left, right int
lc, rc *segmentTreeNode[T]
val T
lazy *T
}
func NewSegmentTree[T any](left, right int, opt *SegmentTreeOption[T]) *SegmentTree[T] {
return &SegmentTree[T]{root: &segmentTreeNode[T]{left: left, right: right, val: opt.InitVal()}, options: opt}
}
func (tree *SegmentTree[T]) pushDown(node *segmentTreeNode[T]) {
if node.lazy == nil {
return
}
mid := (node.left + node.right) >> 1
if node.lc == nil {
node.lc = tree.createNode(node.left, mid)
}
if node.rc == nil {
node.rc = tree.createNode(mid+1, node.right)
}
// 下推更新
node.lc.val = tree.options.MergeVal(node.lc.val, tree.options.UpdateNode(*node.lazy, node.lc.left, node.lc.right))
node.rc.val = tree.options.MergeVal(node.rc.val, tree.options.UpdateNode(*node.lazy, node.rc.left, node.rc.right))
tree.updateLazy(node.lc, *node.lazy)
tree.updateLazy(node.rc, *node.lazy)
// 清空当前节点的 lazy
node.lazy = nil
}
func (tree *SegmentTree[T]) Query(left, right int) T {
return tree.query(tree.root, left, right)
}
func (tree *SegmentTree[T]) query(node *segmentTreeNode[T], left, right int) (ans T) {
if right < node.left || left > node.right {
panic("right out of range or left out of range")
}
if node.left >= left && node.right <= right {
return node.val
}
tree.pushDown(node)
mid := (node.left + node.right) >> 1
if node.lc == nil {
node.lc = tree.createNode(node.left, mid)
}
if node.rc == nil {
node.rc = tree.createNode(mid+1, node.right)
}
if tree.options.InitVal != nil {
ans = tree.options.InitVal()
}
if left <= mid {
ans = tree.options.MergeVal(ans, tree.query(node.lc, left, min(mid, right)))
}
if right > mid {
ans = tree.options.MergeVal(ans, tree.query(node.rc, max(left, mid+1), right))
}
return ans
}
func (tree *SegmentTree[T]) Update(left, right int, val T) {
tree.update(tree.root, left, right, val)
}
func (tree *SegmentTree[T]) update(node *segmentTreeNode[T], left, right int, val T) {
if right < node.left || left > node.right {
return
}
if node.left >= left && node.right <= right {
node.val = tree.options.MergeVal(node.val, tree.options.UpdateNode(val, node.left, node.right))
tree.updateLazy(node, val)
return
}
tree.pushDown(node)
mid := (node.left + node.right) >> 1
if node.lc == nil {
node.lc = tree.createNode(node.left, mid)
}
if node.rc == nil {
node.rc = tree.createNode(mid+1, node.right)
}
if left <= mid {
tree.update(node.lc, left, right, val)
}
if right > mid {
tree.update(node.rc, left, right, val)
}
node.val = tree.options.MergeVal(node.lc.val, node.rc.val)
}
func (tree *SegmentTree[T]) updateLazy(node *segmentTreeNode[T], val T) {
if node.left != node.right {
if node.lazy == nil {
node.lazy = new(T)
*node.lazy = val
} else {
*node.lazy = tree.options.MergeVal(*node.lazy, val)
}
}
}
func (tree *SegmentTree[T]) createNode(left, right int) *segmentTreeNode[T] {
node := &segmentTreeNode[T]{
left: left,
right: right,
}
if tree.options.InitVal != nil {
node.val = tree.options.InitVal()
}
return node
}