【LeetCode】动态规划—931. 下降路径最小和(附完整Python/C++代码)

news2024/9/29 19:59:40

动态规划—931. 下降路径最小和

  • 前言
  • 题目描述
  • 基本思路
    • 1. 问题定义
    • 2. 理解问题和递推关系
    • 3. 解决方法
      • 3.1 动态规划方法
      • 3.2 空间优化的动态规划
    • 4. 进一步优化
      • 4.1 空间复杂度优化
    • 5. 小总结
  • 代码实现
    • Python3代码实现
    • Python 代码解释
    • C++代码实现
    • C++ 代码解释
  • 总结:

前言

在算法的学习中,动态规划是一个至关重要的思想,特别是在解决最优路径问题时,动态规划能够提供一种高效且直观的解决方案。最小下降路径和问题就是这样一个经典的动态规划问题。它要求我们在一个二维矩阵中,从第一行的任意一个元素开始,每次只能向下、左下、右下移动,找到通往最后一行的最小路径和。这类问题不仅在理论上具有挑战性,同时也在实际生活中的路径规划、图像处理等领域有广泛应用。

本文将通过深入剖析最小下降路径和问题,帮助你掌握该类问题的动态规划思路。我们将从问题的定义和递推公式出发,逐步推导解决方法,并提供优化空间复杂度的技巧。同时,本文提供了详细的 Python 和 C++ 代码实现,并对代码进行了逐行解释。无论你是初学者还是有经验的开发者,都可以从本文中获得有益的启发,并加深对动态规划的理解。

希望本文能为你提供清晰的思路,帮助你在解决类似问题时更加得心应手。

题目描述

在这里插入图片描述

基本思路

1. 问题定义

给定一个 n n n * n n n 的方形矩阵 matrix,每个位置都包含一个整数。你可以从矩阵的第一行任何一个元素开始,并逐步向下移动到达最后一行。每次移动时,你只能移动到下一行的同一列、左上方一列或右上方一列的位置。要求你找到从第一行移动到最后一行的最小路径和。

2. 理解问题和递推关系

  • 问题的核心是寻找一条从第一行到最后一行的最小路径和,每次移动只能向下、左下或右下移动。
  • 对于任意位置 ( i , j ) (i, j) (i,j) 的最小路径和 d p [ i ] [ j ] d p[i][j] dp[i][j] ,它可以通过前一行的三个可能位置中的最小值来更新:

d p [ i ] [ j ] = matrix ⁡ [ i ] [ j ] + min ⁡ ( d p [ i − 1 ] [ j ] , d p [ i − 1 ] [ j − 1 ] , d p [ i − 1 ] [ j + 1 ] ) d p[i][j]=\operatorname{matrix}[i][j]+\min (d p[i-1][j], d p[i-1][j-1], d p[i-1][j+1]) dp[i][j]=matrix[i][j]+min(dp[i1][j],dp[i1][j1],dp[i1][j+1])

  • 边界处理:如果位置 ( i − 1 , j − 1 ) (i-1, j-1) (i1,j1) 或 ( i − 1 , j + 1 ) i-1, j+1) i1,j+1) 越界, 忽略该位置。

3. 解决方法

3.1 动态规划方法

  1. 创建一个二维数组 d p d p dp ,其中 d p [ i ] [ j ] d p[i][j] dp[i][j] 表示从第一行到达位置 ( i , j ) (i, j) (i,j) 的最小路径和。
  2. 初始化 d p d p dp 的第一行,直接等于 matrix 的第一行。
  3. 从第二行开始,依次计算每个位置的最小路径和,利用前一行的 dp 值填充当前行的 dp 。
  4. 最终结果为 d p [ n − 1 ] d p[n-1] dp[n1] 中的最小值, 即从第一行到达最后一行的最小路径和。

3.2 空间优化的动态规划

  • 可以使用一维数组代替二维数组 d p d p dp 来节省空间。只需要记录当前行和上一行的最小路径和。

4. 进一步优化

4.1 空间复杂度优化

  • 可以仅使用一维数组保存前一行的最小路径和,逐行更新,降低空间复杂度为 O ( n ) O(n) O(n)

5. 小总结

  • 动态规划是解决此类问题的核心。我们可以通过递推公式求解每一行的最小路径和,逐步构建出全局的最优解。
  • 优化后的空间复杂度可以从 O ( n ∧ 2 ) O\left(n^{\wedge} 2\right) O(n2) 降低到 O ( n ) O(n) O(n) ,这对于大规模矩阵的计算更加高效。

以上就是下降路径最小和问题的基本思路。

代码实现

Python3代码实现

class Solution:
    def minFallingPathSum(self, matrix: list[list[int]]) -> int:
        n = len(matrix)
        # 使用动态规划填充dp数组,第一行等于matrix的第一行
        dp = matrix[0][:]
        
        # 从第二行开始
        for i in range(1, n):
            # 创建一个临时数组存储当前行的最小路径和
            new_dp = [0] * n
            for j in range(n):
                # 当前元素可以从上方、左上方或右上方到达
                min_prev = dp[j]
                if j > 0:
                    min_prev = min(min_prev, dp[j - 1])
                if j < n - 1:
                    min_prev = min(min_prev, dp[j + 1])
                # 更新当前元素的最小路径和
                new_dp[j] = matrix[i][j] + min_prev
            dp = new_dp
        
        # 返回最后一行的最小路径和
        return min(dp)

Python 代码解释

  • 初始化:创建 dp 数组,用于存储前一行的最小路径和。初始化为 matrix 第一行的值。
  • 动态规划递推:从第二行开始,逐行更新 dp。每个位置 (i, j) 的最小路径和通过前一行的三个可能位置 ( d p [ i − 1 ] [ j ] 、 d p [ i − 1 ] [ j − 1 ] 、 d p [ i − 1 ] [ j + 1 ] ) (dp[i-1][j]、dp[i-1][j-1]、dp[i-1][j+1]) dp[i1][j]dp[i1][j1]dp[i1][j+1]中最小的值来更新。
  • 返回结果:最终返回 dp 数组中的最小值,即最后一行的最小路径和。

C++代码实现

class Solution {
public:
    int minFallingPathSum(vector<vector<int>>& matrix) {
        int n = matrix.size();
        // 使用dp数组存储前一行的最小路径和
        vector<int> dp(matrix[0]);

        // 从第二行开始
        for (int i = 1; i < n; ++i) {
            vector<int> new_dp(n, 0);  // 当前行的dp数组
            for (int j = 0; j < n; ++j) {
                int min_prev = dp[j];
                if (j > 0) min_prev = min(min_prev, dp[j - 1]);
                if (j < n - 1) min_prev = min(min_prev, dp[j + 1]);
                new_dp[j] = matrix[i][j] + min_prev;
            }
            dp = new_dp;  // 更新dp为当前行的最小路径和
        }

        // 返回最后一行的最小路径和
        return *min_element(dp.begin(), dp.end());
    }
};

C++ 代码解释

  • 初始化:创建 dp 数组,保存前一行的最小路径和,初始值为 matrix 的第一行。
  • 动态规划递推:从第二行开始,逐行计算每个位置的最小路径和,通过前一行的三个可能位置的最小值更新当前行。
  • 返回结果:遍历最后一行的 dp 数组,返回其中的最小值,即最小路径和。

总结:

  • 时间复杂度:无论是 P y t h o n Python Python 代码还是 C + + C++ C++ 代码,时间复杂度都是 O ( n ∧ 2 ) O\left(n^{\wedge} 2\right) O(n2) ,因为我们需要遍历矩阵的每个元素。
  • 空间复杂度:通过使用一维数组来代替二维 d p d p dp 数组,空间复杂度优化为 O ( n ) O(n) O(n) ,显著减少了内存占用。
  • 动态规划思想:该问题可以通过动态规划思想轻松解决,核心在于计算毎一行的最小路径和,并逐步累积到最后一行。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2177693.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

985官宣:19名本科生,获国自然项目!

9月24日&#xff0c;据复旦大学教务处消息&#xff0c;国家自然科学基金委公布了2024年国家自然科学基金青年学生基础研究项目&#xff08;本科生&#xff09;立项情况&#xff0c;复旦大学共有19名基础学科专业本科生获得国家自然科学基金委资助。 此前&#xff0c;据武汉大学…

VBA技术资料MF207:右键录入指定范围数据

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

比较器(算法中排序)

方式一&#xff1a;不常用 让实体类实现Comparable接口&#xff0c;泛型是需要比较的类型&#xff0c;同时重写compareTo方法 缺点&#xff1a;对代码有侵入性。 public class Student implements Comparable<Student> {private String name;private double score;// …

【YOLOv10改进[SPPF]】使用 SPPFCSPC替换SPPF模块 + 含全部代码和详细修改方式

本文将进行在YOLOv10中使用SPPFCSPC魔改v10 的实践,文中含全部代码、详细修改方式。助您轻松理解改进的方法。 改进前和改进后的参数对比如下: 目录 一 SPPFCSPC 二 使用SPPFCSPC魔改v10的实践 1 整体修改 ① 添加SPPCSPC.py文件 ② 修改ultralytics/nn/tasks.py文件

java中使用selenium自动化测试

一、查看你Chrome浏览器的版本 在浏览器的地址栏&#xff0c;输入chrome://version/&#xff0c;回车后即可查看到对应版本 二、找到对应的chromedriver版本 2.1 114及之前的版本可以通过点击下载chromedriver,根据版本号&#xff08;只看大版本&#xff09;下载对应文件 2.…

运维监控平台:监控易如何实现运维高效管理与大规模监控

在快速变化的数字时代&#xff0c;运维团队正面临着前所未有的挑战。随着企业规模的扩大和IT架构的复杂化&#xff0c;运维团队需要管理的设备数量激增&#xff0c;对系统的稳定性和扩展性提出了更高要求。在这样的背景下&#xff0c;如何高效地进行设备监控&#xff0c;确保系…

pdf分割成多个文件怎么弄?这6个技巧教您学会pdf分割,一看就会!

pdf分割成多个文件怎么弄pdf文件分割成多个文件的需求在办公场景中非常常见。您是否也曾为处理含有多个页面的pdf文件而感到烦恼&#xff1f;不用担心&#xff01;在这篇文章中&#xff0c;小编将和大家分享六个简单易懂的技巧&#xff0c;教您如何轻松将pdf拆分成一页一页的单…

本省第一所!新大学,揭牌!

9月26日&#xff0c;海南艺术职业学院举行揭牌仪式&#xff0c;标志着海南省第一所公办艺术类高等职业院校正式揭牌成立。海南省旅文厅党组成员、副厅长刘成出席揭牌仪式&#xff0c;省教育厅党组成员、副厅长邢孔政在揭牌仪式上宣读省人民政府同意设立海南艺术职业学院的批复。…

【操作系统】三、内存管理:1.存储器管理(程序装入与链接;逻辑地址与物理地址空间;内存保护;交换与覆盖;分页管理方式;分段管理方式;段页式管理方式)

三、内存管理 文章目录 三、内存管理内存基础知识1.分类1.1按在计算机中的作用&#xff08;层次&#xff09;1.2按存储介质1.3按存取方式1.4按信息的可更改性1.5按信息的可保存性 2.存储器的性能指标 六、存储器管理&#xff08;内存管理基础&#xff09;0.内存保护1.程序到程序…

4--苍穹外码-SpringBoot项目中分类管理 详解

前言 1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客 2--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;一&#xff09;-CSDN博客 3--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;二&#xff09;-CSDN博客 4--苍穹外码-SpringBoot项目中分类管理 详…

webGL入门(四)绘制一个三角形

代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><scri…

DBMS-2.3 数据库设计(3)——数据库规范化设计实现(3NF、BCNF模式分解)

本文章的素材与知识来自李国良老师和王珊珊老师。 关系模式分解的定义 一.关系模式分解的定义 1.定义 2.理解 &#xff08;1&#xff09;关系不丢失&#xff1a;所有子关系的属性集加起来 原关系的属性集。即分解中不能把某个属性给丢了。 &#xff08;2&#xff09;模式…

8.6K Star,一键将 Markdown 可视化为思维导图

Hi&#xff0c;骚年&#xff0c;我是大 G&#xff0c;公众号「GitHub 指北」会推荐 GitHub 上有趣有用的项目&#xff0c;一分钟 get 一个优秀的开源项目&#xff0c;挖掘开源的价值&#xff0c;欢迎关注。 在知识管理和项目规划中&#xff0c;思维导图是非常有效的工具&#…

【Flume Kafaka实战】Using Kafka with Flume

一 目标 在Cloudera Manager中创建两个Flume的Agent&#xff0c;Agent1从local file中获取内容&#xff0c;写入到kafka的队列中。Agent2以Agent1的sink作为source&#xff0c;将数据从kafka中读取出来&#xff0c;写入到HDFS中。 二 实战 2.1 Kafka Sink 第一步&#xff0…

Java-数据类型与变量

一、字面常量 在我们使用Java进行数据的打印时&#xff0c;经常会用到这个语句&#xff1a; System.out.println("Hello world!"); 而当这个语句运行时&#xff0c;不论如何都会输出"Hello world!"&#xff0c;所以"Hello world!"就是字面常量…

哪款宠物空气净化器能有效去除浮毛?希喂、352实测分享

你是否曾经站在家电卖场里&#xff0c;面对琳琅满目的宠物空气净化器产品而感到无所适从&#xff1f;或者在浏览网上商城时&#xff0c;被海量的参数和功能描述搞得头晕眼花&#xff1f;别担心&#xff0c;你不是一个人。在这个科技飞速发展的时代&#xff0c;选择一台既能满足…

Grafana指标汉化

1、Grafana解压 目录 conf 2、找到&#xff1a;defaults.ini 3、打开defaults.ini &#xff0c;搜索&#xff1a;en-US 4.重新运行 &#xff1a;grafana-server.exe

开放词汇全景分割

开放词汇全景分割是一种先进的计算机视觉任务&#xff0c;它旨在将图像中的每个像素分割并分类到预先定义或未定义的类别中。这与传统的图像分割不同&#xff0c;后者通常仅限于识别有限的、预先定义的对象类别。开放词汇全景分割的目标是识别和处理图像中的任何可能的对象&…

基于Hadoop的微博舆情监测分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…