王清欢Randy 王清欢Randy
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
首页
  • 编程语言

    • C/C++ 学习笔记
    • Golang 学习笔记
  • 算法分析

    • LeetCode 刷题笔记
  • 操作系统

    • Linux 基础
    • Vim 实用技巧
    • Shell 脚本编程
    • GDB 学习笔记
  • 开发工具

    • Git 学习笔记
  • 分布式理论

    • 共识算法
    • 分布式事务
  • 数据库内核

    • PostgreSQL
    • Postgres-XL
  • hidb
  • pgproxy
  • 实用技巧
  • 学习方法
  • 资源分享
GitHub (opens new window)
  • 基础算法

    • 双指针

      • 双指针基础
      • 碰撞指针
      • 快慢指针
      • 滑动窗口
    • 二分查找

      • 基础应用
      • 边界收缩
      • 局部有序
    • 排序算法

      • 01八大排序
      • 02快速排序
      • 03归并排序
      • 04桶排序
      • 05堆排序
    • 优先搜索

      • 01递归
      • 02网格结构深度优先搜索
      • 03树结构深度优先搜索
      • 04图结构深度优先搜索
      • 05网格结构广度优先搜索
      • 06树结构广度优先搜索
      • 07图结构广度优先搜索
    • 回溯算法

      • 01递归
      • 02 子集问题
      • 03 全排列问题
      • 04 组合问题
      • 05 回溯搜索问题
  • 基础数据结构

    • 线性表与哈希表

      • 01数组
      • 02栈和队列
      • 03单调栈
      • 04优先队列
      • 05双端队列
      • 06哈希表
      • 07多重集合
      • 08前缀和
      • 09数据结构设计
    • 字符串

      • 01字符串比较
      • 02回文字符串
      • 03字符串匹配
      • 04字符串算术表达式
    • 单链表

      • 01链表基础操作
      • 02链表遍历
    • 二叉树

      • 01二叉树的属性
      • 02二叉树的操作
      • 03层次遍历
      • 04前中后序遍历
      • 05二叉搜索树的属性
      • 06二叉搜索树的操作
      • 07字典树
      • 08二叉搜索树BST
    • 图

      • 01二分图
      • 02拓扑排序
      • 03并查集
      • 04最小生成树
      • 05最短路径
  • 进阶算法

    • 贪心算法

      • 01跳跃游戏
      • 02分配问题
      • 03区间问题
    • 分治策略

    • 动态规划

      • 01一维动态规划
      • 02二维动态规划
      • 03分割型动态规划
      • 04子序列问题
      • 05背包问题
      • 06字符串编辑问题
        • 06 字符串编辑问题
          • 72 编辑距离
          • 650 只有两个键的键盘
          • 10 正则表达式匹配
      • 07股票交易问题
  • 其他内容

    • 数学问题

      • 01公倍数与公因数
      • 02质数问题
      • 03进制转换问题
      • 04数字字符串求和问题
      • 05众数问题
      • 06中位数问题
      • 07数字处理问题
      • 08随机数问题
    • 位运算

      • 01位运算基础
      • 02妙用异或运算
      • 03二进制特性
  • LeetCode刷题笔记
  • 进阶算法
  • 动态规划
王清欢
2023-03-24
目录

06字符串编辑问题

# 06 字符串编辑问题

# 72 编辑距离 (opens new window)

​ 给定两个字符串,已知你可以删除、替换和插入任意字符串的任意字符,求最少编辑几步可以将两个字符串变成相同。

​ 输入是两个字符串,输出是一个整数,表示最少的步骤。

输入:word1 = "horse", word2 = "ros" 输出:3 解释: horse -> rorse (将 'h' 替换为 'r') rorse -> rose (删除 'r') rose -> ros (删除 'e')

解析:

​ 本题与最长公共子序列类似,两个字符串的对比所以需要使用一个二维数组来设置状态 dp[i][j]

​ 设置状态:dp[i][j] 表示将第一个字符串到位置 i 为止,和第二个字符串到位置 j 为止,最多需要几步编辑。

​ 状态转移方程:当第 i 位和第 j 位对应的字符相同时,dp[i][j] 等于 dp[i-1][j-1];当二者对应的字符不同时,修改的消耗是 dp[i-1][j-1]+1,插入 i 位置/删除 j 位置的消耗是 dp[i][j-1] + 1,插入 j 位置/删除 i 位置的消耗是 dp[i-1][j] + 1,所以在不同的情况下状态转移方程dp[i][j] = min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])。

​ 边界情况:word1为空串时,需要插入字符与word2一致,即dp[0][j] = j;同理,word2为空串是dp[i][0] = i

class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word1.length(), n = word2.length();
        vector<vector<int>> dp(m+1,vector<int>(n+1));
        // 边界条件 word2为空串
        for(int i=0;i<=m;++i){
            dp[i][0] = i;
        }
        // 边界条件 word1为空串
        for(int j=0;j<=n;++j){
            dp[0][j] = j;
        }
        for(int i=1;i<=m;++i){
            for(int j=1;j<=n;++j){
                // 状态转移,相等情况不编辑,不等情况选择编辑次数最少的编辑
                if(word1[i-1] == word2[j-1]){
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    dp[i][j] = min(dp[i-1][j-1],min(dp[i-1][j],dp[i][j-1])) + 1;
                }
            }
        }
        return dp[m][n];
    }
};

# 650 只有两个键的键盘 (opens new window)

​ 给定一个字母 A,已知你可以每次选择复制全部字符,或者粘贴之前复制的字符,求最少需要几次操作可以把字符串延展到指定长度。

​ 输入是一个正整数,代表指定长度;输出是一个整数,表示最少操作次数。

输入:3 输出:3 解释: 最初, 只有一个字符 'A'。 第 1 步, 使用 Copy All 操作。 第 2 步, 使用 Paste 操作来获得 'AA'。 第 3 步, 使用 Paste 操作来获得 'AAA'。

解析:

​ 不同于以往通过加减实现的动态规划,这里需要乘除法来计算位置,因为粘贴操作是倍数增加的。

​ 设置状态:使用一个一维数组 dp[i],其中位置 i 表示延展到长度 i 的最少操作次数。

​ 状态转移方程:对于每个位置 j,如果 j 可以被 i 整除,那么长度 i 就可以由长度 j 操作得到,其操作次数等价于把一个长度为 1 的 A 延展到长度为 i/j。例如3由1操作得到A A A,6由2操作得到AA AA AA因此可以得到递推公式 dp[i] = dp[j] + dp[i/j]。

class Solution {
public:
    int minSteps(int n) {
        vector<int> dp(n+1);
        for(int i=2;i<=n;++i){
            dp[i] = i;
            for(int j=2;j<=i;++j){
                if(i%j==0){
                    dp[i] = dp[j] + dp[i/j];
                    break;
                }
            }
        }
        return dp[n];
    }
};

# 10 正则表达式匹配 (opens new window)

​ 给定一个字符串和一个正则表达式(regular expression, regex),求该字符串是否可以被匹配,其中'.' 匹配任意单个字符;'*' 匹配零个或多个前面的那一个元素。

​ 输入是一个待匹配字符串和一个用字符串表示的正则表达式,输出是一个布尔值,表示是否可以匹配成功。

输入:s = "aab" p = "cab" 输出:true 解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。

解析:

​ 两个字符串进行匹配,且字符具有特殊含义,本题动态规划的特点在于多种情况下的不同状态转移方程。

​ 设置状态:使用一个布尔类型的二维数组 dp,其中 dp[i][j] 表示以 i 截止的字符串是否可以被以 j 截止的正则表达式匹配。

​ 状态转移方程:根据正则表达式的不同情况,即字符、星号,点号,分情况讨论来更新 dp 数组

  • 相等情况:即s[i-1] == p[j-1] || p[j-1] == '.'的情况,这种情况下dp[i][j] == dp[i-1][j-1],即与前 i-1 个子串匹配情况一致

  • 不相等情况:

    • s[i-1] != p[j-1] && p[j-1] != '*' ,直接不匹配情况dp[i][j] = false
    • p[j-1] == '*':如果匹配0次则dp[i][j-2] == true 则 dp[i][j] = true;如果匹配多次则需要验证'*'前一个字符相等情况即s[i-1] == p[j-1] || p[j-1] == '.',相等则dp[i][j] = dp[i-1][j],否则不匹配

​ 初始情况:空串匹配非空正则表达式,dp[0][0]=true,当p[j-1]=='*'是可以匹配0次匹配空串即dp[0][j] =dp[0][j-2];非空串匹配空正则表达式,dp[0][0]=true,其他情况都无法成功匹配。

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size(), n = p.size();
        vector<vector<bool>> dp(m+1,vector<bool>(n+1,false));
        dp[0][0] = true;
        for(int j=1;j<=n;++j){
            if(p[j-1] == '*'){
                dp[0][j] = dp[0][j-2];
            }
        }

        for(int i=1;i<=m;++i){
            auto chs = s[i-1]; 
            for(int j=1;j<=n;++j){
                auto chp = p[j-1];
                if(chs == chp || chp == '.'){
                    dp[i][j] = dp[i-1][j-1];
                }else if(chp ==  '*'){
                    if(j>1){
                        if(dp[i][j-2]){
                            dp[i][j] = true;
                        }else{
                            auto prechp = p[j-2];
                            if(prechp==chs || prechp =='.'){
                                dp[i][j] = dp[i-1][j];
                            } 
                        }
                    }
                }
            }
        }
        return dp[m][n];
    }
};
上次更新: 2023/11/19, 12:55:48
05背包问题
07股票交易问题

← 05背包问题 07股票交易问题→

Theme by Vdoing | Copyright © 2023-2024 Wang Qinghuan | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式