【动态规划】【记忆化搜索】【回文】1312让字符串成为回文串的最少插入次数

简介: 【动态规划】【记忆化搜索】【回文】1312让字符串成为回文串的最少插入次数

作者推荐

【动态规划】【字符串】【表达式】2019. 解出数学表达式的学生分数

本文涉及知识点

动态规划汇总

记忆化搜索 回文 字符串

LeetCode1312. 让字符串成为回文串的最少插入次数

给你一个字符串 s ,每一次操作你都可以在字符串的任意位置插入任意字符。

请你返回让 s 成为回文串的 最少操作次数 。

「回文串」是正读和反读都相同的字符串。

示例 1:

输入:s = “zzazz”

输出:0

解释:字符串 “zzazz” 已经是回文串了,所以不需要做任何插入操作。

示例 2:

输入:s = “mbadm”

输出:2

解释:字符串可变为 “mbdadbm” 或者 “mdbabdm” 。

示例 3:

输入:s = “leetcode”

输出:5

解释:插入 5 个字符后字符串变为 “leetcodocteel” 。

提示:

1 <= s.length <= 500

s 中所有字符都是小写字母。

动态规划

动态规划的状态表示

dp[left][r] 表示s[left,r]变成回文需要插入的字符数。

动态规划的转移方程

d p [ l e f t ] [ r ] = m i n { d p [ l e f t + 1 ] [ r − 1 ] s [ l e f t ] = = s [ r ] d p [ l e f t + 1 ] [ r ] + 1 d p [ l e f t ] [ r − 1 ] + 1 dp[left][r]=min\begin{cases} dp[left+1][r-1] & s[left]==s[r] \\ dp[left+1][r]+1 & \\ dp[left][r-1]+1 & \\ \end{cases}dp[left][r]=mindp[left+1][r1]dp[left+1][r]+1dp[left][r1]+1s[left]==s[r]

用Cal函数代替dp向量:一,方便记忆。二,方便处理left > r。

动态规划的初始值

全为-1,表示未处理。

动态规划的填表顺序

递归计算dp[0][n-1]

动态规划的返回值

dp[0][n-1]

代码

核心代码

class Solution {
public:
  int minInsertions(string s) {
    const int n = s.length();
    vector<vector<int>> dp(n, vector<int>(n, -1));
    return Cal(dp,s,0, n - 1);
  }
  int Cal (vector<vector<int>>& dp ,const string& s,int left, int r)
  {
    if (left > r)
    {
      return 0;
    }
    if (-1 != dp[left][r])
    {
      return dp[left][r];
    }
    if (s[left] == s[r])
    {
      return dp[left][r] = Cal(dp,s,left + 1, r - 1);
    }
    return dp[left][r] = min(Cal(dp, s, left + 1, r) + 1, Cal(dp, s, left, r - 1) + 1);
  };
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{
  assert(t1 == t2);
}
template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
  if (v1.size() != v2.size())
  {
    assert(false);
    return;
  }
  for (int i = 0; i < v1.size(); i++)
  {
    Assert(v1[i], v2[i]);
  }
}
int main()
{ 
  string s;
  {
    Solution sln;
    s = "zzazz";
    auto res = sln.minInsertions(s);
    Assert(0, res);
  }
  {
    Solution sln;
    s = "mbadm";
    auto res = sln.minInsertions(s);
    Assert(2, res);
  }
  {
    Solution sln;
    s = "leetcode";
    auto res = sln.minInsertions(s);
    Assert(5, res);
  }
}

2023年2月第一版

class Solution {

public:

int minInsertions(string s) {

return s.length() - MaxNum(s);

}

int MaxNum(string s)

{

int c = s.length();

vector<vector> dp(c+1, vector©);

for (int j = 0; j < c; j++)

{

dp[1][j] = 1;

}

for (int len = 2; len <= c; len++)

{

for (int i = 0; i + len <= c; i++)

{

dp[len][i] = max(dp[len-1][i] ,dp[len-1][i+1]);

if (s[i] == s[i + len - 1])

{

dp[len][i] = max(dp[len][i], 2 + dp[len - 2][i + 1]);

}

}

}

return dp[c][0];

}

};

2023年2月 第二版

class Solution {

public:

int minInsertions(string s) {

string strInv(s.rbegin(), s.rend());

return s.length() - longestCommonSubsequence(s, strInv);

}

int longestCommonSubsequence(string text1, string text2) {

vector pre(text1.size()+1);

for (int i = 1; i <= text2.length(); i++)

{

vector dp(text1.size() + 1);

for (int j = 1; j <= text1.size();j++ )

{

dp[j] = max(pre[j], dp[j - 1]);

if (text2[i - 1] == text1[j - 1])

{

dp[j] = max(dp[j], pre[j - 1]+1);

}

}

pre.swap(dp);

}

return pre.back();

}

};

2023年7月版

class Solution {

public:

int minInsertions(string s) {

for (int i = 0; i <= s.length(); i++)

{

for (int j = 0; j <= s.length(); j++)

{

m_result[i][j] = -1;

}

}

return minInsertions(s, 0, s.length());

}

//左闭右开

int minInsertions(const string& s, int left, int r)

{

if (r - left <= 1)

{

return 0;

}

int& result = m_result[left][r];

if (-1 != result)

{

return result;

}

if (s[left] == s[r - 1])

{

return result =minInsertions(s, left + 1, r - 1);

}

return result = 1 + min(minInsertions(s, left + 1, r), minInsertions(s, left, r - 1));

}

int m_result[501][501];

};


相关文章
|
6月前
|
机器学习/深度学习 测试技术 Windows
【动态规划】【回文】【字符串】1147. 段式回文
【动态规划】【回文】【字符串】1147. 段式回文
|
6月前
|
算法 测试技术 C#
【字符串】【贪心】【 树状数组】2193. 得到回文串的最少操作次数
【字符串】【贪心】【 树状数组】2193. 得到回文串的最少操作次数
|
6月前
|
机器学习/深度学习 算法 测试技术
【字符串】【分类讨论】【KMP】1163. 按字典序排在最后的子串
【字符串】【分类讨论】【KMP】1163. 按字典序排在最后的子串
|
6月前
|
算法
【面试算法——动态规划 19】最长回文子序列&& (hard)让字符串成为回文串的最少插入次数
【面试算法——动态规划 19】最长回文子序列&& (hard)让字符串成为回文串的最少插入次数
|
6月前
|
人工智能 算法 BI
【前缀和】【分类讨论】【二分查找】2983:回文串重新排列查询
【前缀和】【分类讨论】【二分查找】2983:回文串重新排列查询
|
6月前
|
算法 测试技术 C#
【单调栈 】LeetCode321:拼接最大数
【单调栈 】LeetCode321:拼接最大数
|
6月前
【每日一题Day226】L1156单字符重复子串的最大长度 | 贪心+滑动窗口
【每日一题Day226】L1156单字符重复子串的最大长度 | 贪心+滑动窗口
56 0
|
算法
【算法专题突破】双指针 - 无重复字符的最长子串(10)
【算法专题突破】双指针 - 无重复字符的最长子串(10)
34 0
|
算法 C++
剑指offer(C++)-JZ48:最长不含重复字符的子字符串(算法-动态规划)
剑指offer(C++)-JZ48:最长不含重复字符的子字符串(算法-动态规划)
|
算法 搜索推荐
【算法】非递归堆排序判断字符串中所有字符是否只出现一次
【算法】非递归堆排序判断字符串中所有字符是否只出现一次
50 0