news 2026/4/23 13:04:35

算法题 下降路径最小和

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
算法题 下降路径最小和

931. 下降路径最小和

问题描述

给你一个n x n的方形整数数组matrix,请你找出并返回通过matrix下降路径的最小和。

下降路径的定义:

  • 从第一行的任意元素开始
  • 每一步可以移动到下一行的相邻列(即列号为j-1jj+1,但不能超出边界)
  • 到达最后一行结束

示例

输入: matrix = [[2,1,3],[6,5,4],[7,8,9]] 输出: 13 解释: 最小下降路径为 [1,4,8],和为13。 输入: matrix = [[-19,57],[-40,-5]] 输出: -59 解释: 最小下降路径为 [-19,-40],和为-59。

算法思路

动态规划(自底向上)

状态定义

  • dp[i][j]表示从位置(i, j)到最后一行的最小下降路径和

状态转移方程

  • 对于最后一行:dp[n-1][j] = matrix[n-1][j]
  • 对于其他行:dp[i][j] = matrix[i][j] + min(dp[i+1][j-1], dp[i+1][j], dp[i+1][j+1])
  • 需要处理边界情况(j-1 >= 0j+1 < n

代码实现

方法一:动态规划

classSolution{/** * 计算下降路径的最小和 * * @param matrix n x n 的整数矩阵 * @return 下降路径的最小和 */publicintminFallingPathSum(int[][]matrix){intn=matrix.length;if(n==1)returnmatrix[0][0];// dp[i][j] 表示从(i,j)到最后一行的最小下降路径和int[][]dp=newint[n][n];// 初始化最后一行for(intj=0;j<n;j++){dp[n-1][j]=matrix[n-1][j];}// 自底向上填充DP表for(inti=n-2;i>=0;i--){for(intj=0;j<n;j++){// 找到下一行中相邻列的最小值intminNext=dp[i+1][j];// 正下方// 左下方(如果存在)if(j>0){minNext=Math.min(minNext,dp[i+1][j-1]);}// 右下方(如果存在)if(j<n-1){minNext=Math.min(minNext,dp[i+1][j+1]);}dp[i][j]=matrix[i][j]+minNext;}}// 找到第一行中的最小值intresult=dp[0][0];for(intj=1;j<n;j++){result=Math.min(result,dp[0][j]);}returnresult;}}

方法二:滚动数组

classSolution{/** * 使用滚动数组 */publicintminFallingPathSum(int[][]matrix){intn=matrix.length;if(n==1)returnmatrix[0][0];// 只需要保存下一行的结果int[]nextRow=newint[n];int[]currentRow=newint[n];// 初始化最后一行for(intj=0;j<n;j++){nextRow[j]=matrix[n-1][j];}// 自底向上计算for(inti=n-2;i>=0;i--){for(intj=0;j<n;j++){intminNext=nextRow[j];if(j>0){minNext=Math.min(minNext,nextRow[j-1]);}if(j<n-1){minNext=Math.min(minNext,nextRow[j+1]);}currentRow[j]=matrix[i][j]+minNext;}// 交换数组引用int[]temp=nextRow;nextRow=currentRow;currentRow=temp;}// nextRow 现在包含第一行的结果intresult=nextRow[0];for(intj=1;j<n;j++){result=Math.min(result,nextRow[j]);}returnresult;}}

方法三:自顶向下递归 + 记忆化

classSolution{privateint[][]memo;privateint[][]matrix;privateintn;/** * 自顶向下递归 + 记忆化 */publicintminFallingPathSum(int[][]matrix){this.matrix=matrix;this.n=matrix.length;if(n==1)returnmatrix[0][0];this.memo=newint[n][n];for(inti=0;i<n;i++){Arrays.fill(memo[i],Integer.MAX_VALUE);}intresult=Integer.MAX_VALUE;// 从第一行的每个位置开始for(intj=0;j<n;j++){result=Math.min(result,dfs(0,j));}returnresult;}/** * 递归函数:计算从(i,j)开始的最小下降路径和 */privateintdfs(inti,intj){// 边界检查if(i>=n||j<0||j>=n){returnInteger.MAX_VALUE;}// 到达最后一行if(i==n-1){returnmatrix[i][j];}// 记忆化if(memo[i][j]!=Integer.MAX_VALUE){returnmemo[i][j];}// 递归计算三个方向intleft=dfs(i+1,j-1);intdown=dfs(i+1,j);intright=dfs(i+1,j+1);intminNext=Math.min(Math.min(left,down),right);memo[i][j]=matrix[i][j]+minNext;returnmemo[i][j];}}

算法分析

方法时间复杂度空间复杂度
DPO(n²)O(n²)
滚动数组O(n²)O(n)
记忆化递归O(n²)O(n²)

算法过程

输入:matrix = [[2,1,3],[6,5,4],[7,8,9]]

方法一

  1. 初始化最后一行:dp[2] = [7,8,9]
  2. 计算第1行:
    • dp[1][0] = 6 + min(7,8) = 13
    • dp[1][1] = 5 + min(7,8,9) = 12
    • dp[1][2] = 4 + min(8,9) = 12
  3. 计算第0行:
    • dp[0][0] = 2 + min(13,12) = 14
    • dp[0][1] = 1 + min(13,12,12) = 13
    • dp[0][2] = 3 + min(12,12) = 15
  4. 结果:min(14,13,15) = 13

输入:matrix = [[-19,57],[-40,-5]]

  1. dp[1] = [-40,-5]
  2. dp[0][0] = -19 + (-40) = -59
  3. dp[0][1] = 57 + min(-40,-5) = 52
  4. 结果:min(-59,52) = -59

测试用例

publicstaticvoidmain(String[]args){Solutionsolution=newSolution();// 测试用例1:标准示例int[][]matrix1={{2,1,3},{6,5,4},{7,8,9}};System.out.println("Test 1: "+solution.minFallingPathSum(matrix1));// 13// 测试用例2:负数int[][]matrix2={{-19,57},{-40,-5}};System.out.println("Test 2: "+solution.minFallingPathSum(matrix2));// -59// 测试用例3:单元素int[][]matrix3={{5}};System.out.println("Test 3: "+solution.minFallingPathSum(matrix3));// 5// 测试用例4:全负数int[][]matrix4={{-1,-2,-3},{-4,-5,-6},{-7,-8,-9}};System.out.println("Test 4: "+solution.minFallingPathSum(matrix4));// -18// 测试用例5:全正数int[][]matrix5={{1,2,3},{4,5,6},{7,8,9}};System.out.println("Test 5: "+solution.minFallingPathSum(matrix5));// 12// 测试用例6:大数值int[][]matrix6={{100,200,300},{400,500,600},{700,800,900}};System.out.println("Test 6: "+solution.minFallingPathSum(matrix6));// 1200// 测试用例7:混合正负int[][]matrix7={{1,-1,1},{-1,1,-1},{1,-1,1}};System.out.println("Test 7: "+solution.minFallingPathSum(matrix7));// -1// 测试用例8:4x4矩阵int[][]matrix8={{1,2,3,4},{5,6,7,8},{9,10,11,12},{13,14,15,16}};System.out.println("Test 8: "+solution.minFallingPathSum(matrix8));// 28}

关键点

  1. 动态规划

    • 自底向上更直观,每个位置只依赖下一行
    • 自顶向下需要处理多个起点
  2. 边界处理

    • 第一列没有左下方
    • 最后一列没有右下方
    • 需要分别处理这些边界情况
  3. 初始化

    • 最后一行是基础情况,直接等于原矩阵值

常见问题

  1. 为什么不用自顶向下的DP?
    • 自顶向下需要为每个起点都计算一次
    • 自底向上一次遍历就能得到所有位置的最优解
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 13:02:54

Qwen2.5-0.5B教育应用案例:智能辅导系统搭建

Qwen2.5-0.5B教育应用案例&#xff1a;智能辅导系统搭建 1. 引言 1.1 教育智能化的迫切需求 随着在线教育和个性化学习的快速发展&#xff0c;传统“一刀切”的教学模式已难以满足多样化、个性化的学习需求。学生在学习过程中面临知识理解不深、问题反馈延迟、缺乏即时互动等…

作者头像 李华
网站建设 2026/4/16 14:03:03

Windows 7还能用!VxKex实现Edge浏览器及现代应用兼容方案

作为后端开发工程师或长期使用旧系统的运维人员&#xff0c;你是否常被“软件启动报dll错误”“Win7无法运行新版应用”“老旧系统生态支持弱”等问题影响效率&#xff1f;今天分享的这款技术工具&#xff0c;能针对性解决这些实操难题。 【VxKex】「适配环境&#xff1a;Wind…

作者头像 李华
网站建设 2026/4/18 18:44:31

学术论文实体提取怎么做?Qwen3-0.6B给出答案

学术论文实体提取怎么做&#xff1f;Qwen3-0.6B给出答案 1. 引言&#xff1a;学术论文实体提取的挑战与技术演进 在科研信息化和知识图谱构建日益重要的今天&#xff0c;从海量学术文献中自动提取结构化信息已成为自然语言处理的关键任务。传统的信息抽取方法依赖于规则模板或…

作者头像 李华
网站建设 2026/4/23 11:21:59

腾讯混元翻译模型应用:HY-MT1.5-1.8B在医疗翻译中的实践

腾讯混元翻译模型应用&#xff1a;HY-MT1.5-1.8B在医疗翻译中的实践 1. 引言 随着全球医疗合作的不断深化&#xff0c;跨语言医学文献、病历记录和临床指南的高效准确翻译成为推动国际医疗协作的关键环节。传统机器翻译系统在通用领域表现良好&#xff0c;但在专业性强、术语…

作者头像 李华
网站建设 2026/4/3 1:10:42

NewBie-image-Exp0.1效果展示:3.5B模型生成的动漫作品

NewBie-image-Exp0.1效果展示&#xff1a;3.5B模型生成的动漫作品 1. 技术背景与核心价值 近年来&#xff0c;大规模扩散模型在图像生成领域取得了显著进展&#xff0c;尤其是在动漫风格图像生成方向&#xff0c;高质量、可控性强的模型需求日益增长。然而&#xff0c;许多开…

作者头像 李华
网站建设 2026/4/23 11:23:16

2026 AI语音落地实战:开源ASR模型+弹性GPU部署趋势详解

2026 AI语音落地实战&#xff1a;开源ASR模型弹性GPU部署趋势详解 1. 引言&#xff1a;中文语音识别的工程化落地挑战 随着大模型与智能硬件的深度融合&#xff0c;语音交互正成为人机沟通的核心入口。在客服、会议记录、教育转写等场景中&#xff0c;高精度、低延迟的自动语…

作者头像 李华