力扣hot100 | 多维动态规划 | 62. 不同路径、64. 最小路径和、5. 最长回文子串、1143. 最长公共子序列、72. 编辑距离

62. 不同路径

力扣题目链接

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 "Start" )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 "Finish" )。

问总共有多少条不同的路径?

  • 【思路】
python 复制代码
# from functools import cache
from functools import lru_cache as cache # 3.9以下的版本

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        @cache
        def dfs(i, j): # 表示从(0,0)走到(i,j)的路径数
            if i < 0 or j < 0:  # 无法从(0,0)走到这些位置
                return 0
            if i == 0 and j == 0: # dfs(0, 0) 原地不动是一种办法
                return 1
            return dfs(i-1, j) + dfs(i, j-1)
        return dfs(m-1, n-1)
  • 时间复杂度 O(mn)
  • 空间复杂度 O(mn)

64. 最小路径和

力扣题目链接

给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

参考自灵茶山艾府

python 复制代码
# from functools import cache
from functools import lru_cache as cache # 3.9以下的版本

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        @cache 
        def dfs(i: int, j: int) -> int:
            if i < 0 or j < 0:
                return inf
            if i == 0 and j == 0:
                return grid[i][j]
            return min(dfs(i, j - 1), dfs(i - 1, j)) + grid[i][j]
        return dfs(len(grid) - 1, len(grid[0]) - 1)
  • 时间复杂度 O(mn) ,其中 m 和 n 分别为 grid 的行数和列数。由于每个状态只会计算一次,动态规划的时间复杂度 = 状态个数 × 单个状态的计算时间。本题状态个数等于 O(mn),单个状态的计算时间为 O(1),所以总的时间复杂度为 O(mn)。
  • 空间复杂度 O(mn),保存多少状态,就需要多少空间。

5. 最长回文子串

力扣题目链接

给你一个字符串 s,找到 s 中最长的 回文 子串。

示例 1:

输入:s = "babad"

输出:"bab"

解释:"aba" 同样是符合题意的答案。
示例 2:

输入:s = "cbbd"

输出:"bb"

中心扩散法

参考自灵茶山艾府

写法一:奇偶分开判断

python 复制代码
class Solution:
    def longestPalindrome(self, s: str) -> str:
        n = len(s)
        ans_left = ans_right = 0

        # 奇回文串
        for i in range(n):
            l = r = i
            while l >= 0 and r < n and s[l] == s[r]:
                l -= 1
                r += 1
            # 循环结束后,s[l+1] 到 s[r-1] 是回文串
            if r - l - 1 > ans_right - ans_left:
                ans_left, ans_right = l + 1, r  # 左闭右开区间

        # 偶回文串
        for i in range(n - 1):
            l, r = i, i + 1
            while l >= 0 and r < n and s[l] == s[r]:
                l -= 1
                r += 1
            if r - l - 1 > ans_right - ans_left:
                ans_left, ans_right = l + 1, r  # 左闭右开区间

        return s[ans_left: ans_right]
  • 时间复杂度 O(n^2)
  • 空间复杂度 O(1)

1143. 最长公共子序列

力扣题目链接

给定两个字符串 text1text2,返回这两个字符串的最长公共子序列 的长度。如果不存在公共子序列 ,返回0

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的子序列,但 "aec" 不是 "abcde" 的子序列。

两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:

输入:text1 = "abcde", text2 = "ace"

输出:3

解释:最长公共子序列是 "ace" ,它的长度为 3 。
示例 2:

输入:text1 = "abc", text2 = "abc"

输出:3

解释:最长公共子序列是 "abc" ,它的长度为 3 。
示例 3:

输入:text1 = "abc", text2 = "def"

输出:0

解释:两个字符串没有公共子序列,返回 0 。

参考自灵茶山艾府

python 复制代码
# from functools import cache
from functools import lru_cache as cache # 3.9以下的版本

class Solution:
    def longestCommonSubsequence(self, s: str, t: str) -> int:
        n, m = len(s), len(t)
        @cache 
        def dfs(i: int, j: int) -> int: # s[:i+1]与t[:j+1]的最长公共子序列长度
            if i < 0 or j < 0:
                return 0
            if s[i] == t[j]:
                return dfs(i - 1, j - 1) + 1
            return max(dfs(i - 1, j), dfs(i, j - 1))
        return dfs(n - 1, m - 1)
  • 时间复杂度 O(nm)
  • 空间复杂度 O(nm)

72. 编辑距离

力扣题目链接

给你两个单词 word1word2, 请返回将 word1 转换成 word2 所使用的最少操作数

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

示例 1:

输入:word1 = "horse", word2 = "ros"

输出:3

解释:

horse -> rorse (将 'h' 替换为 'r')

rorse -> rose (删除 'r')

rose -> ros (删除 'e')
示例 2:

输入:word1 = "intention", word2 = "execution"

输出:5

解释:

intention -> inention (删除 't')

inention -> enention (将 'i' 替换为 'e')

enention -> exention (将 'n' 替换为 'x')

exention -> exection (将 'n' 替换为 'c')

exection -> execution (插入 'u')

参考自灵茶山艾府

python 复制代码
# from functools import cache
from functools import lru_cache as cache # 3.9以下的版本

class Solution:
    def minDistance(self, s: str, t: str) -> int:
        n, m = len(s), len(t)
        @cache 
        def dfs(i: int, j: int) -> int: # 将word1[:i+1]转成word2[:j+1]的最少操作数
            if i < 0:
                return j + 1
            if j < 0:
                return i + 1
            if s[i] == t[j]:
                return dfs(i - 1, j - 1)
            return min(dfs(i - 1, j), dfs(i, j - 1), dfs(i - 1, j - 1)) + 1
        return dfs(n - 1, m - 1)
  • 时间复杂度 O(mn),其中 n 为 s 的长度,m 为 t 的长度。
  • 空间复杂度 O(mn)
相关推荐
Neverfadeaway几秒前
【C语言】深入理解函数指针数组应用(4)
c语言·开发语言·算法·回调函数·转移表·c语言实现计算器
Madison-No744 分钟前
【C++】探秘vector的底层实现
java·c++·算法
Swift社区1 小时前
LeetCode 401 - 二进制手表
算法·leetcode·ssh
派大星爱吃猫1 小时前
顺序表算法题(LeetCode)
算法·leetcode·职场和发展
liu****1 小时前
8.list的模拟实现
linux·数据结构·c++·算法·list
地平线开发者2 小时前
征程 6 | 征程 6 工具链如何支持 Matmul/Conv 双 int16 输入量化?
算法·自动驾驶
程序员大雄学编程3 小时前
「深度学习笔记4」深度学习优化算法完全指南:从梯度下降到Adam的实战详解
笔记·深度学习·算法·机器学习
小O的算法实验室3 小时前
2022年ASOC SCI2区TOP,基于竞争与合作策略的金字塔粒子群算法PPSO,深度解析+性能实测,深度解析+性能实测
算法·论文复现·智能算法·智能算法改进
南莺莺4 小时前
邻接矩阵的基本操作
数据结构·算法··邻接矩阵
微波仿真4 小时前
实现多通道ADC多次测量取平均值,使用DMA
算法