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

Swift 解法详解 LeetCode 363:矩形区域不超过 K 的最大数值和

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

文章目录

    • 摘要
    • 描述
    • 题解答案
    • 题解代码分析
      • 代码拆解
    • 示例测试及结果
    • 时间复杂度
    • 空间复杂度
    • 总结

摘要

这道题的名字听上去有点“硬核数学”,但其实本质就是:在一个二维矩阵里找一个子矩形,这个子矩形的元素和要尽可能大,但同时又不能超过一个给定的阈值 K。
现实中你可能会遇到类似问题:

  • 数据分析里,我们需要找出某个时间区间内的最大收益,但不能超过某个风控上限。
  • 在游戏里,可能要计算玩家在地图某个范围内收集的金币,不能超过背包容量。

今天我们就把这个题目拆开来讲,从暴力到优化,最后写出一个 Swift Demo 带你跑一遍。

描述

题目要求:

给定一个 m x n 的矩阵和一个整数 k,请找出矩阵中 不超过 k 的最大子矩形和

示例:

输入: matrix = [[1,0,1],[0,-2,3]], k = 2
输出: 2
解释: 子矩形 [[0, -2], [1, 3]] 的和是 2,正好等于 k。

注意:

  • 子矩形就是连续的行和列围起来的一个小区域。
  • 我们需要考虑所有可能的矩形组合。
  • 题目难点在于矩阵可能很大,如果用暴力解法会超时。

题解答案

直观思路:

  1. 先固定矩阵的上下边界,把问题转化为一维数组的「子数组和不超过 k 的最大值」。
  2. 然后用前缀和 + 有序数据结构来加速查找。
  3. 最终得到的解法就是“枚举上下边界 + 求解一维子数组最大和”。

题解代码分析

下面是 Swift 代码实现(附带详细注释):

import Foundationclass Solution {func maxSumSubmatrix(_ matrix: [[Int]], _ k: Int) -> Int {let m = matrix.countlet n = matrix[0].countvar res = Int.min// 枚举左右边界for left in 0..<n {var rowSum = Array(repeating: 0, count: m)for right in left..<n {// 更新每行的区间和for i in 0..<m {rowSum[i] += matrix[i][right]}// 在 rowSum 里找不超过 k 的最大子数组和res = max(res, maxSubArrayNoMoreThanK(rowSum, k))if res == k { return res } // 提前结束}}return res}// 求一维数组中不超过k的最大子数组和private func maxSubArrayNoMoreThanK(_ nums: [Int], _ k: Int) -> Int {var prefix = 0var res = Int.minvar prefixSet = [0]for num in nums {prefix += num// 二分查找,找 >= prefix - k 的最小前缀和var left = 0, right = prefixSet.count - 1var candidate: Int? = nilwhile left <= right {let mid = (left + right) / 2if prefixSet[mid] >= prefix - k {candidate = prefixSet[mid]right = mid - 1} else {left = mid + 1}}if let cand = candidate {res = max(res, prefix - cand)}// 插入保持有序insertSorted(&prefixSet, prefix)}return res}// 插入有序数组private func insertSorted(_ arr: inout [Int], _ val: Int) {var l = 0, r = arr.countwhile l < r {let mid = (l + r) / 2if arr[mid] < val {l = mid + 1} else {r = mid}}arr.insert(val, at: l)}
}// Demo 演示
let solution = Solution()
let matrix = [[1,0,1],[0,-2,3]]
let k = 2
print("矩阵中不超过 \(k) 的最大矩形和是: \(solution.maxSumSubmatrix(matrix, k))")

代码拆解

  1. 固定左右边界
    我们从左列到右列一层层扩展,把二维问题降成一维。

  2. 构建 rowSum
    rowSum 表示在当前左右边界下,每行的列和。

  3. 一维问题求解
    这时候问题变成了「找一维数组的最大子数组和,且不超过 k」。

    • 用前缀和来快速求区间和。
    • 用一个有序数组存储前缀和,方便二分查找。
  4. 插入有序数组
    保证 prefixSet 始终有序,这样才能用二分查找高效找到候选值。

示例测试及结果

运行上面的 Demo,会输出:

矩阵中不超过 2 的最大矩形和是: 2

你可以再试试:

let matrix2 = [[2,2,-1]]
print(solution.maxSumSubmatrix(matrix2, 3)) // 输出 3

这个例子里,矩阵只有一行,子数组 [2, -1] 的和是 1,小于等于 3,但最大的是 [2, 2, -1] = 3,正好等于 k。

时间复杂度

  • 外层固定左右边界:O(n²)。
  • 内层处理 rowSum:O(m)。
  • 一维子数组求解:O(m log m)。
    总复杂度:O(n² * m log m),其中 m 是行数,n 是列数。

空间复杂度

  • rowSum 占用 O(m)。
  • prefixSet 在最坏情况下 O(m)。
    总空间复杂度:O(m)

总结

这道题表面看是矩阵题,但真正的突破点在于把二维问题转成一维,再利用「前缀和 + 二分」解决。

这类题很有工程意义:

  • 数据库里统计一段时间窗口内的数据总和上限。
  • 金融风控里计算收益不能超过阈值的区间。
  • 游戏设计里限制玩家的行为值上限。

所以说,不只是 LeetCode,这种滑动窗口 + 前缀和的思维方式,在日常开发里用处非常广。

http://www.dtcms.com/a/351562.html

相关文章:

  • Unity游戏打包——Mac基本环境杂记
  • Android Glide生命周期管理:实现原理与最佳实践
  • ubuntu2204安装搜狗拼音输入法
  • 基于spark的招聘岗位需求分析可视化系统设计与实现
  • 《相关法律、法规知识(五)》
  • 【数据结构】串——模式匹配
  • 微服务-23.网关登录校验-自定义GlobalFilter
  • yggjs_rbutton React按钮组件v1.0.0 示例和教程
  • Java全栈开发面试实录:从基础到实战的深度探索
  • JVM 学习与提升路线总结:从入门到精通的系统化指南
  • 前端-如何将前端页面输出为PDF并打包的压缩包中
  • PDF转图片、图片转PDF(免费)
  • AI+drawio生成流程图探索
  • Python 操作 PPT 文件:从新手到高手的实战指南
  • 重构审计体验!批量生成报表项目底稿的凭证检查表
  • 计算机术语 / 数学术语中的 trivial 与 non-trivial
  • MD5校验算法
  • Node.js(3)—— fs模块
  • Docker:部署Java后端
  • 关于电脑连接手机热点没有网络的问题
  • 每日一题DEEP_ML-卡方分布(Chi-Squared Distribution)
  • 数据结构初阶:详解单链表(一)
  • Linux->多线程3
  • Ubuntu操作系统下MySQL、MongoDB、Redis
  • 如何拯救一家濒临破产的科技公司?
  • C++工程实战入门笔记5-函数(二)
  • React前端开发_Day1
  • 迅为R3588S开发板ADB使用手册-运行shell
  • ctfshow_萌新web16-web20-----文件包含日志注入
  • 运算符(1)