首页 > 编程语言 >Python面试宝典第19题:最小路径和

Python面试宝典第19题:最小路径和

时间:2024-07-27 16:28:26浏览次数:20  
标签:19 memo 路径 宝典 最小 Python grid 数组 dp

题目

        给定一个包含非负整数的m x n网格grid,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。说明:每次只能向下或者向右移动一步。

        示例 1:

输入:grid = [[1, 3, 1], [1, 5, 1], [4, 2, 1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

        示例 2:

输入:grid = [[1, 2, 3], [4, 5, 6]]
输出:12

记忆化递归法

        记忆化递归法的核心思想是将递归过程中遇到的子问题及其解存储起来,即记忆化,以便在后续遇到相同子问题时直接查表获取结果,避免重复计算。针对本题,我们将使用一个二维数组memo来存储到达每个格子的最小路径和。使用记忆化递归法求解本题的主要步骤如下。

        1、初始化记忆数组。创建一个与原网格大小相同的二维数组memo,全部初始化为一个特殊值(如None或极大值),表示尚未计算。

        2、定义递归函数。编写一个递归函数,输入参数为当前坐标(i, j),该函数计算从(i, j)到右下角的最小路径和。递归的基本情况是当(i, j)位于右下角时,直接返回该格子的值。

        3、记忆化处理。在递归函数内部,首先检查memo[i][j]是否已被计算过,若已计算则直接返回该值。

        4、递归计算。否则,计算最小路径和,即分别计算从当前位置向下和向右移动的最小路径和,取二者中较小者加上当前位置的值。

        5、更新记忆数组。将计算出的最小路径和存入memo[i][j]。

        6、调用递归函数。从起点(0, 0)开始,调用递归函数。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def minimum_path_sum_by_recursion(grid):
    def helper(i, j):
        # 基本情况:到达右下角
        if i == m - 1 and j == n - 1:
            return grid[i][j]
        
        # 已经计算过的情况,直接返回结果
        if memo[i][j] is not None:
            return memo[i][j]
        
        # 向下或向右移动的最小路径和
        if i < m - 1 and j < n - 1:
            memo[i][j] = grid[i][j] + min(helper(i+1, j), helper(i, j+1))
        elif i < m - 1:
            # 只能向下
            memo[i][j] = grid[i][j] + helper(i+1, j)
        else:
            # 只能向右
            memo[i][j] = grid[i][j] + helper(i, j+1)
        
        return memo[i][j]
    
    if not grid or not grid[0]:
        return 0

    m, n = len(grid), len(grid[0])
    # 初始化记忆数组
    memo = [[None]*n for _ in range(m)]
    # 从起点开始调用递归函数
    return helper(0, 0)

grid = [[1, 3, 1], [1, 5, 1], [4, 2, 1]]
print(minimum_path_sum_by_recursion(grid))

grid = [[1, 2, 3], [4, 5, 6]]
print(minimum_path_sum_by_recursion(grid))

动态规划法

        动态规划法的核心思想在于解决具有重叠子问题和最优子结构的问题。对于本题,我们要找的是从左上角到右下角的最小路径和。每一步只能向右或向下移动,这意味着到达任何一个格子的最小路径和,都是从其左边或上边的格子通过一步移动过来的最小路径和加上当前格子的值。因此,我们可以从左上角开始,逐步构建一个二维数组来存储到达每个格子的最小路径和。使用动态规划法求解本题的主要步骤如下。

        1、初始化。创建一个与原网格相同大小的二维数组dp,其中dp[0][0] = grid[0][0],表示起点的最小路径和就是它本身的值。

        2、边界条件。对于第一行的所有单元格,其最小路径和等于从上一列的相应单元格移动下来的值加上当前单元格的值。同理,第一列的所有单元格也是如此处理。

        3、状态转移方程。对于dp[i][j](其中i>0且j>0),其值应为min(dp[i-1][j], dp[i][j-1]) + grid[i][j],即到达当前格子的最小路径和等于其上方格子和左侧格子的最小路径和中的较小者,再加上当前格子的值。

        4、最终结果。dp[m-1][n-1]即为从左上角到右下角的最小路径和。

        根据上面的算法步骤,我们可以得出下面的示例代码。

def minimum_path_sum_by_dp(grid):
    if not grid or not grid[0]:
        return 0
    
    m, n = len(grid), len(grid[0])
    # 初始化dp数组
    dp = [[0]*n for _ in range(m)]
    
    # 初始化dp数组的第一行和第一列
    dp[0][0] = grid[0][0]
    for i in range(1, m):
        dp[i][0] = dp[i-1][0] + grid[i][0]
    for j in range(1, n):
        dp[0][j] = dp[0][j-1] + grid[0][j]
    
    # 根据状态转移方程填充dp数组
    for i in range(1, m):
        for j in range(1, n):
            dp[i][j] = min(dp[i-1][j], dp[i][j-1]) + grid[i][j]
    
    return dp[m-1][n-1]

grid = [[1, 3, 1], [1, 5, 1], [4, 2, 1]]
print(minimum_path_sum_by_dp(grid))

grid = [[1, 2, 3], [4, 5, 6]]
print(minimum_path_sum_by_dp(grid))

总结

        记忆化递归法和动态规划法的时间复杂度均为O(m*n),其中m和n分别是网格的行数和列数。这是因为,每个单元格最多被访问一次。两者的空间复杂度也一样,均为O(m*n), 需要一个与原网格大小相同的二维数组来存储中间结果。

        动态规划法还可以通过使用一维数组(滚动数组)来优化空间复杂度至 O(n)。这是因为,每一行的计算只需要前一行的信息,而不需要保留整个二维数组。对于每行,我们只需维护一个长度为n的一维数组。这样在计算完一行后,可以复用该数组空间来存储下一行的计算结果。

标签:19,memo,路径,宝典,最小,Python,grid,数组,dp
From: https://blog.csdn.net/hope_wisdom/article/details/140678957

相关文章

  • 基于python的出租车管理网站的设计与实现【源码+文档+PPT】
    ......
  • 如何在Linux上的python中以后台模式打开程序?
    我需要在Linux上以后台模式使用python打开另一个程序。我尝试过subprocess.call("yourcommand")但它不是后台模式。并且os.startfile("file")在Linux上不起作用。请帮助我。可以使用Python的subprocess模块在Linux上以后台模......
  • 【学习笔记】Matlab和python双语言的学习(TOPSIS法)
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言一、TOPSIS法1.模型原理2.基本步骤(1)原始矩阵正向化(2)正向矩阵标准化(3)计算得分并归一化二、代码实现----Matlab1.主程序2.正向化处理函数3.极小型正向化函数4.中间型正向化函数5.区间型正向化......
  • 基于Python flask 的豆瓣电影top250数据评分可视化
    跟着CSDN上学习一下爬虫和简单的可视化分析,最后完成了一个简单的小项目。1.项目简介        基于Pythonflask的豆瓣电影评分可视化。通过采用Python编程语言,使用flask框架搭建影视系统,并使用相关技术实现对豆瓣网站的爬取、数据存储和可视化分析。2、成果展示:......
  • 获取 Python Decimal 的精确十进制字符串表示形式?
    如果我有一个PythonDecimal,我怎样才能可靠地获得数字的精确十进制字符串(即不是科学记数法)表示而不带尾随零?例如,如果我有:>>>d=Decimal('1e-14')我会像:>>>get_decimal_string(d)'0.00000000000001'但是:Decimal类没有任何to_......
  • python datetime timedelta 对于没有小数部分的时间返回 0.0
    我正在使用datetime.timedelta来获取python中进程的持续时间。defget_time_difference(start_time,end_time):time_in_seconds=(end_time-start_time)returnstr(datetime.timedelta(seconds=time_in_seconds))[:-3]文档指出“所有参数都是可选的......
  • 如何运行从我正在编写的另一个 Python 脚本获取命令行参数的 Python 脚本?
    我有一个python3脚本,如下所示:...defmain():parser=argparse.ArgumentParser(description='Performnormalisationchecksonpass2files')parser.add_argument('-p','--parser',action='store',help='parse......
  • 每日一题- CF1995D
    唐氏小状压#include<bits/stdc++.h>usingnamespacestd;#definelowbit(x)(x&-(x))intt,n,c,k,cnt[(1<<18)+5][35];boolf[(1<<18)+5];chars[(1<<18)+5];intcalc(intx){ intres=0; while(x)x^=lowbit(x),res++; returnres;}voidi......
  • Python 抓取 urllib2 HTTP 错误
    我正在尝试抓取一个网站,但我的代码仅在我打开该网站然后刷新它时才有效。我尝试了多种方法,但不断出现以下两个错误:第一个:ValueError:“HTTPError:HTTP错误416:请求的范围无法满足”urlslist=open("list_urls.txt").read()urlslist=urlslist.split("\n")forurlslistinurl......
  • 【Python】利用 face_recognition 库进行人脸检测识别【附完整示例】
    1.背景条件1.1安装所需库首先安装face_recognition和Pillow这两个库。您可以使用以下命令来安装它们:pipinstallface_recognitionPillow-ihttps://pypi.tuna.tsinghua.edu.cn/simple1.2拷贝代码安装完成后,您就可以在本地运行以下提供的代码了。importfac......