当前位置: 首页 > news >正文

Swift 解锁数组可修改场景:LeetCode 307 高效解法全解析

在这里插入图片描述
在这里插入图片描述

文章目录

    • 摘要
    • 描述
    • 题解答案(Swift 实现 – 树状数组版)
    • 题解代码分析
      • 为什么选择树状数组?
      • 初始化和更新逻辑
      • 区间和查询
    • 示例测试及结果
    • 时间复杂度
    • 空间复杂度
    • 总结

摘要

在很多业务场景中,数据不仅要查询区间和,还会被实时修改。比如商城的库存系统、在线游戏中的积分榜,甚至是股票价格的区间统计。LeetCode 第 307 题正是针对这种“可修改+可查询”场景设计的,它要求你设计一个数据结构支持快速更新数组中的某个位置,同时还能高效查询任意区间的和。

本篇文章我们使用 Swift 实现两种经典数据结构方案:树状数组(Fenwick Tree)线段树,并提供可运行代码、思路分析和示例演示,帮助你真正掌握区间查询加更新的优化思路。

描述

题目的要求是这样的:

设计一个 NumArray 类,它支持:

  1. 初始化一个整数数组 nums
  2. 方法 update(index, val) 用来修改数组中 nums[index] 的值;
  3. 方法 sumRange(left, right) 返回当前数组在 [left, right] 范围内所有元素的和。

数组长度可达 3*10^4,操作次数也最多如此,如果每次 sumRange 都遍历数组,效率会非常低。我们需要在支撑快速更新的前提下,实现常数或对数级别的查询。

题解答案(Swift 实现 – 树状数组版)

我们首先给出使用 树状数组(Fenwick Tree)实现的代码,结构简洁,运行高效:

import Foundationclass NumArray {private var nums: [Int]private var bit: [Int]private let n: Intinit(_ nums: [Int]) {self.nums = numsn = nums.countbit = Array(repeating: 0, count: n + 1)for i in 0..<n {initUpdate(i, nums[i])}}private func initUpdate(_ idx: Int, _ val: Int) {var i = idx + 1while i <= n {bit[i] += vali += i & -i}}func update(_ index: Int, _ val: Int) {let diff = val - nums[index]nums[index] = valvar i = index + 1while i <= n {bit[i] += diffi += i & -i}}private func prefixSum(_ idx: Int) -> Int {var sum = 0var i = idx + 1while i > 0 {sum += bit[i]i -= i & -i}return sum}func sumRange(_ left: Int, _ right: Int) -> Int {return prefixSum(right) - (left > 0 ? prefixSum(left - 1) : 0)}
}

此外,如果更喜欢面向范围分治的思想,也可以用线段树实现。但本文重心放在 Fenwick Tree,代码更简洁高效。

题解代码分析

为什么选择树状数组?

树状数组适合支持两类操作:

  • 对单点进行增量更新(O(log n));
  • 查询前缀和(O(log n))。

正好满足“两类操作都频繁”的场景,比起每次重新累加数组快得多,且实现相比线段树要简单。

初始化和更新逻辑

  • 初始化时,我们先清 BIT(全 0),然后通过 initUpdate 方法把每个元素累加到 BIT 中;
  • 更新时,调整 nums[index],并计算差值 diff,然后用 while 根据 BIT 的结构逐级更新影响范围。

区间和查询

通过两个前缀和差值:

sumRange(l, r) = prefixSum(r) - prefixSum(l - 1)

其中 prefixSum(idx) 用标准的 BIT 查询方式累加相关节点即可。

示例测试及结果

我们可以建立几个测试用例,用来验证代码正确性:

let numArray = NumArray([1, 3, 5])
print(numArray.sumRange(0, 2))  // 输出 9
numArray.update(1, 2)           // nums 变为 [1,2,5]
print(numArray.sumRange(0, 2))  // 输出 8// 更多测试
let arr = NumArray([0,1,2,3,4])
print(arr.sumRange(1,3))        // 输出 6
arr.update(2, 10)
print(arr.sumRange(1,3))        // 输出 1+10+3=14

测试结果完全符合预期,并且执行速度非常快。

时间复杂度

  • 初始化:构建 BIT 时为 O(n log n)
  • 每次 updateO(log n)
  • 每次 sumRange:两次前缀和查询,各 O(log n),总共 O(log n)

总操作次数 ≤ 3*10^4,logn 在数万量级下也在 15 左右,性能远超过暴力方法。

空间复杂度

  • 存储原始数组 numsO(n)
  • 存储 BIT 数组:O(n + 1)
  • 总空间复杂度约为:O(n)

这非常适合内存充足的现代设备。

总结

  • 树状数组 是解决“支持更新+快速求前缀和”类问题的高效工具;
  • 通过巧妙利用二进制分段求和原理,实现每次查询 O(log n)
  • 实际应用场景非常多,比如滑动窗口交易统计、用户访问计数、时序分析等;
  • 如果你想处理更加复杂的区间更新或区间查询,也可以继续学习线段树、差分数组、BIT 范畴进阶。

相关文章:

  • 【软考高级系统架构论文】企业集成平台的技术与应用
  • shell脚本--条件判断
  • uniswap v4 账本式结算与账户余额管理机制解析
  • Wire--编译时依赖注入工具
  • 系统思考VS心智模式
  • Jupyter notebook调试:设置断点运行
  • 网站自助广告投放系统源码 附安装教程(源码下载)
  • 3.9 局部规划器
  • Kubernetes控制平面组件:Kubelet详解(八):容器存储接口 CSI
  • AI评测-(1)基础介绍
  • 【Docker 08】Compose - 容器编排
  • 【单调栈】-----【Largest Rectangle in a Histogram】
  • DPO直接偏好函数的学习解读
  • 【Kubernetes】从零搭建K8s集群:虚拟机环境配置全指南(DNS/网络/防火墙/SELinux全解析一站式配置图文教程)
  • Spring中IoC的理解
  • python模块常用语法sys、traceback、QApplication
  • [muduo] Buffer缓冲区 | TcpServer | Reactor模式
  • 在 `setup` 函数中实现路由跳转:Vue3与Vue Router 4的集成
  • Python 数据分析与可视化 Day 3 - Pandas 数据筛选与排序操作
  • vivado工具配置(二)
  • 物流公司网站建设/郑州网站设计有哪些
  • 网站快照/软件培训班学费多少
  • 网页设计网站/软文广告500字
  • 甘肃做网站价格/网络推广公司是干嘛的
  • 做网站的备案/百度热榜
  • wordpress 数据 拆分/排名优化方法