跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

力扣 1749 题:任意子数组和的绝对值的最大值(DP 与前缀和)

力扣 1749 题要求计算任意子数组和的绝对值的最大值,可通过前缀和与动态规划解决。前缀和法利用最大与最小前缀差值;动态规划维护以当前位置结尾的最大和最小子数组和,支持空间优化。最终结果为两者绝对值的最大值。

樱花落尽发布于 2026/2/26更新于 2026/10/19106 浏览
力扣 1749 题:任意子数组和的绝对值的最大值(DP 与前缀和)

方法 1:前缀和

思路

这道题要找 nums 数组中和的绝对值最大的任意子数组,子数组的问题,我们可以使用前缀和的思想来做,假设前缀和数组是 s。

  • 那么子区间的前缀和绝对值可以这样表示:|s[j] - s[i]|
  • 我们不难发现,s[j] 跟 s[i] 相差越大,上式也就越大。
  • 因此我们只需要找 s 数组中的最大前缀和跟最小前缀和,然后求差即可:max(s) - min(s)
  • 因为存在负数的情况,貌似不好理解,所以可以分两种情况理解,在 s 数组中:
    • 如果最大前缀和出现在最小前缀和的右边,那么上式算的是最大子数组和。
    • 如果最大前缀和出现在最小前缀和的左边,那么上式算的是最小子数组和的绝对值。

还有一个更好理解的方式,就是想象是在爬山,本质上就是在计算最大的高度差。

拿案例 1 举例:

输入:nums = [1,-3,2,3,-4] 输出:5 
代码如下
class Solution {
    public int maxAbsoluteSum(int[] nums) {
        int n = nums.length;
        int s = 0;
        int max = 0;
        int min = 0;
        for (int i = 0; i < n; i++) {
            s += nums[i];
            // 效率更高的写法
            if (max < s) {
                max = s;
            } else if (s < min) {
                min = s;
            }
        }
        return max - min;
    }
}

方法 2:动态规划

这道题也可以使用动态规划的写法,这道题属于线性的动态规划。

思路
  1. 考虑以 nums[i] 结尾的最大子数组和(以 nums[i] 结尾的最小子数组逻辑是一样的)
    • 如果子数组只有自己一个数,那么最大子数组和就是 nums[i]
    • 如果跟前面拼接起来,那么就变成了求更小的子问题:求以 nums[i-1] 结尾的最大子数组和
  2. 定义状态:
    • 设 f[i] 为以 nums[i] 结尾的最大子数组和。
    • 设 g[i] 为以 nums[i] 结尾的最小子数组和。
  3. 状态转移方程:
    • 最大值: f[i] = max(f[i-1] + nums[i], nums[i])
      • 意为:要么接在前面的最大和后面,要么自己重新开始。
    • 最小值: g[i] = min(g[i-1] + nums[i], nums[i])
      • 意为:要么接在前面的最小和后面,要么自己重新开始。
  4. 最终答案:
    • maxSum = max(maxSum, f[i])
    • minSum = min(minSum, g[i])

最后返回:max(maxSum, -minSum)

代码
class Solution {
    public int maxAbsoluteSum(int[] nums) {
        int n = nums.length;
        // 表示以 nums[i] 结尾的最大子数组和
        int[] f = new int[n];
        // 表示以 nums[i] 结尾的最小子数组和
        int[] g = new int[n];
        // 初始化
        f[0] = nums[0];
        g[0] = nums[0];
        int ans = Math.abs(nums[0]);
        for (int i = 1; i < n; i++) {
            // 状态转移:要么接上前面的,要么从当前推倒重来
            f[i] = Math.max(nums[i], f[i-1] + nums[i]);
            g[i] = Math.min(nums[i], g[i-1] + nums[i]);
            // 当前最大和、当前最小和的绝对值、以及之前的最大绝对值
            ans = Math.max(ans, Math.max(f[i], -g[i]));
        }
        return ans;
    }
}

这个方法好理解一下,我们也可以更优雅的写法:使用空间优化的方法,如下:

空间优化的写法

因为求 f[i] 的公式是:f[i] = max(nums[i], f[i-1] + nums[i])

f[i] 只根据前一次的数据 f[i-1],至于更早的数据,对于 i 来说都不需要,所以,我们可以使用滚动变量的方式进行空间优化:

class Solution {
    public int maxAbsoluteSum(int[] nums) {
        // 1. 先显式初始化第一个元素
        int fMax = nums[0];
        int fMin = nums[0];
        int ans = Math.abs(nums[0]);
        // 2. 从 i = 1 开始循环
        for (int i = 1; i < nums.length; i++) {
            int x = nums[i];
            fMax = Math.max(x, fMax + x);
            fMin = Math.min(x, fMin + x);
            ans = Math.max(ans, Math.max(fMax, -fMin));
        }
        return ans;
    }
}

或者:

  • 不使用空间优化时,状态转移方程是:f[i] = max(nums[i], f[i-1] + nums[i])
  • 这个方程可以提取出 nums[i],写成:f[i] = max(0, f[i-1]) + nums[i]

所以当你使用空间优化,把数组 f[i] 变成变量 fMax 时,代码可以写成:

fMax = Math.max(fMax, 0) + x;

且在第一轮循环结束后,fMax 和 fMin 都会被'强制校准'为数组的第一个元素

class Solution {
    public int maxAbsoluteSum(int[] nums) {
        int ans = 0, fMax = 0, fMin = 0;
        for (int x : nums) {
            fMax = Math.max(fMax, 0) + x;
            fMin = Math.min(fMin, 0) + x;
            ans = Math.max(ans, Math.max(fMax, -fMin));
        }
        return ans;
    }
}

目录

  1. 方法 1:前缀和
  2. 思路
  3. 代码如下
  4. 方法 2:动态规划
  5. 思路
  6. 代码
  7. 空间优化的写法

更多推荐文章

查看全部
  • 淘特 App x-sign 签名逆向分析:从抓包到算法还原
  • 2026 年 3 月大模型全景解析:国产登顶与 Agent 工业化落地
  • 拓竹P1S封神玩法|AI图生3D+精准修改全攻略,打孔/挖盖再也不用瞎琢磨!
  • 交换排序详解:从冒泡优化到快速排序四种实现
  • StableDiffusion-webui 本地部署与使用指南
  • C++ 测试与调试:保障代码质量与稳定性
  • 自然语言处理(NLP)在客户服务中的应用与实战
  • FPGA 千兆以太网 SGMII 接口配置实战
  • MongoDB 数据备份与恢复实战指南
  • Spring Cloud 配置中心选型实战:Nacos vs Apollo vs Spring Cloud Config
  • 前端 AI 编码共享插件:Claude Code / Codex / OpenClaw 工作流实践
  • AI 时代后端程序员开发前端的技术选型与实践
  • C++ 性能优化实战指南
  • GitHub 镜像站推荐及国内访问加速方案
  • ClawPanel:OpenClaw 智能管理面板,支持多通道接入与多模型配置
  • Linux 下 Docker 版本升级操作指南
  • Neo4j Desktop 2.0 安装及自定义路径配置指南
  • C++ 继承入门:从基础概念到默认成员函数
  • C++ 哈希表原理与线性探测、哈希桶模拟实现
  • 基于 AutoGPT 与 Python 的 AI 智能体开发实战

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online