当前位置: 首页 > 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.xdnf.cn/news/1371313.html

相关文章:

  • Spring Bean 生命周期高阶用法:从回调到框架级扩展
  • Java基础第5天总结(final关键字,枚举,抽象类)
  • CVPR自适应卷积的高效实现:小核大感受野提升复杂场景下图像重建精度
  • vue新增用户密码框自动将当前用户的密码自动填充的问题
  • 高校党建系统设计与实现(代码+数据库+LW)
  • 嵌入式配置数据序列化:自定义 TLV vs nanopb
  • 深度学习篇---LeNet-5
  • 1Panel命令
  • 100种交易系统(6)均线MA识别信号与杂音
  • 深度学习----由手写数字识别案例来认识PyTorch框架
  • Python实现RANSAC进行点云直线、平面、曲面、圆、球体和圆柱拟合
  • Il2CppInspector 工具linux编译使用
  • 设计模式之命令模式
  • Vuex 和 Pinia 各自的优点
  • Linux之SELinux 概述、SSH 密钥登录、服务器初始化
  • 利用AI进行ArcGISPro进行数据库的相关处理?
  • Java数据结构速成【1】
  • 原则性 单一职责原则,第一性原则和ACID原则 : 安全/学习/节约
  • 从双重检查锁定的设计意图、锁的作用、第一次检查提升性能的原理三个角度,详细拆解单例模式的逻辑
  • Markdown学习笔记(4)
  • 矩阵微积分的链式法则(chain rule)
  • 在 Android Studio 中修改 APK 启动图标(2025826)
  • 从线到机:AI 与多模态交互如何重塑 B 端与 App 界面设计
  • 【RAGFlow代码详解-23】聊天系统架构
  • 【LeetCode 热题 100】75. 颜色分类——双指针
  • PWM控制实现呼吸灯
  • 家庭财务规划与投资系统的设计与实现(代码+数据库+LW)
  • Linux SSH 基于密钥交换的自动登录:原理与配置指南
  • (Arxiv-2024)VideoMaker:零样本定制化视频生成,依托于视频扩散模型的内在力量
  • 进程管理详解