news 2026/8/14 16:11:18

Kimi LeetCode 3901. 好子序列查询 Golang实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Kimi LeetCode 3901. 好子序列查询 Golang实现

根据搜索结果,LeetCode 3901「好子序列查询」的 Go 实现如下:

---

思路

1. 只关心 p 的倍数:如果 `nums[i]` 不是 `p` 的倍数,它对 GCD 为 `p` 的子序列没有贡献,在线段树中视为 `0`。
2. 线段树维护所有 p 倍数的 GCD:记为 `g`。
- 若 `g != p`,则不存在好子序列。
- 若 `g == p`,则所有 p 的倍数整体 GCD 已是 `p`。
3. 长度严格小于 n:
- 若 `cnt < n`(并非所有元素都是 p 的倍数),直接取所有 p 的倍数即可,长度必然 `< n`。
- 若 `cnt == n`(所有元素都是 p 的倍数),需要删一个元素后 GCD 仍为 `p`。
- 关键结论:若 `n > 6` 且整体 GCD 为 `p`,则一定可以删一个元素使 GCD 仍为 `p`。因此只需在 `n <= 6` 时暴力枚举删除位置。
4. 线段树操作:单点更新、区间查询 GCD。

---

Go 实现

```go
func gcd(a, b int) int {
for b != 0 {
a, b = b, a%b
}
return a
}

type Node struct {
l, r int
g int
}

func NewNode(l, r int) *Node {
return &Node{l: l, r: r, g: 0}
}

type SegmentTree struct {
tr []*Node
}

func NewSegmentTree(n int) *SegmentTree {
tree := &SegmentTree{tr: make([]*Node, n<<2)}
tree.build(1, 1, n)
return tree
}

func (st *SegmentTree) build(u, l, r int) {
st.tr[u] = NewNode(l, r)
if l == r {
return
}
mid := (l + r) >> 1
st.build(u<<1, l, mid)
st.build(u<<1|1, mid+1, r)
}

func (st *SegmentTree) pushup(u int) {
st.tr[u].g = gcd(st.tr[u<<1].g, st.tr[u<<1|1].g)
}

func (st *SegmentTree) modify(u, x, v int) {
if st.tr[u].l == st.tr[u].r {
st.tr[u].g = v
return
}
mid := (st.tr[u].l + st.tr[u].r) >> 1
if x <= mid {
st.modify(u<<1, x, v)
} else {
st.modify(u<<1|1, x, v)
}
st.pushup(u)
}

func (st *SegmentTree) query(u, l, r int) int {
if l > r {
return 0
}
if st.tr[u].l >= l && st.tr[u].r <= r {
return st.tr[u].g
}
mid := (st.tr[u].l + st.tr[u].r) >> 1
if r <= mid {
return st.query(u<<1, l, r)
}
if l > mid {
return st.query(u<<1|1, l, r)
}
return gcd(st.query(u<<1, l, mid), st.query(u<<1|1, mid+1, r))
}

func countGoodSubseq(nums []int, p int, queries [][]int) int {
n := len(nums)
tree := NewSegmentTree(n)
cnt := 0
for i, x := range nums {
if x%p == 0 {
tree.modify(1, i+1, x)
cnt++
}
}

ans := 0
for _, q := range queries {
idx, val := q[0], q[1]
if nums[idx]%p == 0 {
tree.modify(1, idx+1, 0)
cnt--
}
if val%p == 0 {
tree.modify(1, idx+1, val)
cnt++
}
nums[idx] = val

if tree.tr[1].g != p {
continue
}
if cnt < n || n > 6 {
ans++
continue
}
for i := 1; i <= n; i++ {
leftG := tree.query(1, 1, i-1)
rightG := tree.query(1, i+1, n)
if gcd(leftG, rightG) == p {
ans++
break
}
}
}
return ans
}
```

---

复杂度

- 时间复杂度:O((n + q) \times \log n),其中 n \le 6 时的暴力枚举是常数级。
- 空间复杂度:O(n)。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 16:11:07

学习笔记 | Linux多线程基础:从线程创建到资源回收

一&#xff0c;为什么需要多线程 1.1 什么是线程 进程是资源分配的最小单位&#xff0c;线程是CPU调度的最小单位。 一个进程内部可以创建多个线程&#xff0c;所有线程共享该进程的地址空间&#xff0c;全局变量&#xff0c;文件描述符&#xff1b;每个线程都由自己独立栈&…

作者头像 李华
网站建设 2026/8/14 15:58:50

7.vue指令3

内容v-if, v-else,v-else-if步骤添加数据添加标签添加指令<p v-if"number1">性别男</p> <p v-else>性别女</p>注意else需要紧挨if使用不能单独存在显示内容在<p></p>中间v-else-if用于复杂场景注意两个数据之间要用,(英&#xf…

作者头像 李华
网站建设 2026/8/14 15:57:16

3分钟装完全部VC++运行库:VisualCppRedist AIO 快速上手指南

3分钟装完全部VC运行库&#xff1a;VisualCppRedist AIO 快速上手指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 上周五晚上&#xff0c;我打开一个下载了两…

作者头像 李华
网站建设 2026/8/14 15:55:03

社区健身小程序开发实战:从需求分析到上线全流程指南

社区健身小程序开发实战&#xff1a;从需求分析到上线全流程指南 在全民健身与数字化社区深度融合的背景下&#xff0c;“社区健身”小程序已成为连接居民、物业与健身资源的核心载体。针对“社区健身”这一关键词&#xff0c;本文将从技术选型、数据建模、核心功能实现到部署上…

作者头像 李华