【动态规划】【记忆化搜索】【C++算法】664. 奇怪的打印机

简介: 【动态规划】【记忆化搜索】【C++算法】664. 奇怪的打印机

LeetCode:664 奇怪的打印机

有台奇怪的打印机有以下两个特殊要求:

打印机每次只能打印由 同一个字符 组成的序列。

每次可以在从起始到结束的任意位置打印新字符,并且会覆盖掉原来已有的字符。

给你一个字符串 s ,你的任务是计算这个打印机打印它需要的最少打印次数。

示例 1:

输入:s = “aaabbb”

输出:2

解释:首先打印 “aaa” 然后打印 “bbb”。

示例 2:

输入:s = “aba”

输出:2

解释:首先打印 “aaa” 然后在第二个位置打印 “b” 覆盖掉原来的字符 ‘a’。

提示:

1 <= s.length <= 100

s 由小写英文字母组成

动态规划

空间复杂度😮(n2)

时间复杂度: O(n3)

小技巧: 两个挨着的字符相同可以删除一个,不影响结果。因为打印的次数不限。 此技巧使用可以稍稍提速,不使用也没问题。

动态规范的状态表示:dp[left][r]表示 让s[left,r]符合要求的最少次数。

动态规划的转移方程:必定有一次覆盖s[left],此次覆盖可以分以下两种情况:

  • 除s[i]外,没有盖其它字符或其它字符被新的印章覆盖。dp[left][r]=1 + dp[left+1][r]
  • 除s[left]外,还有字符没覆盖,假定其下标最小的为s[i],则没印章跨越s[i],故s(l,r)可以独立出来。dp[left][r] = dp[left+1,i-1]+dp[i][r]
    动态规划的初始状态: 全部为0,表示未处理。
    动态规划的填表顺序:枚举left。
    动态规划的返回值:dp[0][n-1]

代码

核心代码

class Solution {
public:
  int strangePrinter(string s) {    
    for (int i = 0; i < s.length(); i++)
    {
      if ((0 == i) || (s[i] != s[i - 1]))
      {
        m_s += s[i];
      }
    } 
    m_c = m_s.length();
    m_dp.assign(m_c, vector<int>(m_c));
    return Cal(0, m_c - 1);
  }
  int Cal(int left,int r)
  {
    if (left > r)
    {
      return 0;
    }
    if (0 != m_dp[left][r])
    {
      return m_dp[left][r];
    }
    int iRet = 1 + Cal(left + 1,r);
    for (int i = left+1 ; i <= r; i++)
    {
      if (m_s[i] == m_s[left])
      {
        iRet = min(iRet,  Cal(left + 1, i - 1) + Cal(i, r));
      }
    }
    return m_dp[left][r] = iRet;
  }
  int m_c;
  string m_s;
  vector<vector<int>> m_dp;
};

测试用例

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 = "a";
    auto res = sln.strangePrinter(s);
    Assert(1, res);
  }
  {
    Solution sln;
    s = "aaaa";
    auto res = sln.strangePrinter(s);
    Assert(1, res);
  }
  {
    Solution sln;
    s = "aaabbb";
    auto res = sln.strangePrinter(s);
    Assert(2, res);
  }
  {
    Solution sln;
    s = "aba";
    auto res = sln.strangePrinter(s);
    Assert(2, res);
  }
  {
    Solution sln;
    s = "aabab";
    auto res = sln.strangePrinter(s);
    Assert(3, res);
  }
  {
    Solution sln;
    s = "aabacdaa";
    auto res = sln.strangePrinter(s);
    Assert(4, res);
  }
  {
    Solution sln;
    s = "acdddda";
    auto res = sln.strangePrinter(s);
    Assert(3, res);
  }
}

2023年一月版

class Solution {
public:
int strangePrinter(string s) {
m_c = s.length();
m_dp.assign(m_c + 1, vector(m_c,INT_MAX));
{
int len = 1;
for (int c = 0; c + len - 1 < m_c; c++)
{
m_dp[len][c] = 1;
}
}
for (int len = 2; len <= m_c; len++)
{
for (int c = 0; c + len - 1 < m_c; c++)
{
const int iEnd = c + len - 1;
if ((s[c] == s[iEnd]) || (s[iEnd] == s[iEnd - 1]))
{
m_dp[len][c] = m_dp[len - 1][c];
continue;
}
for (int iPreLen = 1; iPreLen < len; iPreLen++)
{
m_dp[len][c] = min(m_dp[len][c],m_dp[iPreLen][c] + m_dp[len - iPreLen][c + iPreLen]);
}
}
}
return m_dp[m_c][0];
}
vector m_dp;
int m_c;
};

2023年6月版

class Solution {
public:
int strangePrinter(string s) {
m_c = s.length();
memset(m_LenBegin, 0, sizeof(m_LenBegin));
for (int begin = 0; begin < m_c; begin++)
{
m_LenBegin[1][begin] = 1;
}
for (int len = 2; len <= m_c; len++)
  {
    for (int begin = 0; begin + len - 1 < m_c; begin++)
    {
      const int end = begin + len - 1;
      if (s[begin] == s[end])
      {
        m_LenBegin[len][begin] = m_LenBegin[len - 1][begin];
        continue;
      }
      int iNum = INT_MAX;
      for (int leftLen = 1; leftLen < len; leftLen++)
      {
        iNum = min(iNum, m_LenBegin[leftLen][begin] + m_LenBegin[len - leftLen][begin + leftLen]);
      }
      m_LenBegin[len][begin] = iNum;
    }
  }
  return m_LenBegin[m_c][0];
}
int m_c;
int m_LenBegin[100+1][100];

};

2023年7月版

class Solution {
public:
int strangePrinter(string s) {
m_c = s.length();
vector vLenBegin(m_c + 1, vector(m_c+1,1));
for (int len = 2; len <= m_c; len++)
{
for (int begin = 0; begin < m_c; begin++)
{
const int end = begin + len - 1;
if (end >= m_c)
{
continue;
}
if (s[begin] == s[end])
{
vLenBegin[len][begin] = vLenBegin[len-1][begin];
continue;
}
int iNum = INT_MAX;
for (int leftLen=1 ;leftLen < len ; leftLen++ )
{
iNum = min(vLenBegin[leftLen][begin] + vLenBegin[len - leftLen][begin + leftLen], iNum);
}
vLenBegin[len][begin] = iNum;
}
}
return vLenBegin[m_c][0];
}
int m_c;
};

2023年8月版

class Solution {
public:
int strangePrinter(string s) {
m_c = s.length();
m_vLeftRight.assign(m_c, vector(m_c,INT_MAX));
//任何印章方式都可以转成,第一次处理最右端元素
for (int len = 1; len <= m_c; len++)
{
#define END (left + len - 1)
for (int left = 0; END < m_c; left++)
{
if (1 == len)
{
m_vLeftRight[left][END] = 1;
continue;
}
for (int mid = left; mid < END; mid++)
{
m_vLeftRight[left][END] = min(m_vLeftRight[left][END], m_vLeftRight[left][mid] + m_vLeftRight[mid + 1][END] - (s[mid] == s[END]));
}
}
}
return m_vLeftRight.front().back();
}
int m_c;
vector m_vLeftRight;
};


扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。

https://edu.csdn.net/course/detail/38771

如何你想快

速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程

https://edu.csdn.net/lecturer/6176

相关

下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版

https://download.csdn.net/download/he_zhidan/88348653

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 **C+

+17**

如无特殊说明,本算法用**C++**实现。

目录
打赏
0
0
0
0
36
分享
相关文章
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
29 8
解读 C++ 助力的局域网监控电脑网络连接算法
本文探讨了使用C++语言实现局域网监控电脑中网络连接监控的算法。通过将局域网的拓扑结构建模为图(Graph)数据结构,每台电脑作为顶点,网络连接作为边,可高效管理与监控动态变化的网络连接。文章展示了基于深度优先搜索(DFS)的连通性检测算法,用于判断两节点间是否存在路径,助力故障排查与流量优化。C++的高效性能结合图算法,为保障网络秩序与信息安全提供了坚实基础,未来可进一步优化以应对无线网络等新挑战。
公司局域网管理中的哈希表查找优化 C++ 算法探究
在数字化办公环境中,公司局域网管理至关重要。哈希表作为一种高效的数据结构,通过哈希函数将关键值(如IP地址、账号)映射到数组索引,实现快速的插入、删除与查找操作。例如,在员工登录验证和设备信息管理中,哈希表能显著提升效率,避免传统线性查找的低效问题。本文以C++为例,展示了哈希表在局域网管理中的具体应用,包括设备MAC地址与IP分配的存储与查询,并探讨了优化哈希函数和扩容策略,确保网络管理高效准确。
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
54 15
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
31 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
算法系列之搜索算法-深度优先搜索DFS
深度优先搜索和广度优先搜索一样,都是对图进行搜索的算法,目的也都是从起点开始搜索,直到到达顶点。深度优先搜索会沿着一条路径不断的往下搜索,直到不能够在继续为止,然后在折返,开始搜索下一条候补路径。
113 62
算法系列之搜索算法-深度优先搜索DFS
|
2月前
|
算法系列之搜索算法-广度优先搜索BFS
广度优先搜索(BFS)是一种非常强大的算法,特别适用于解决最短路径、层次遍历和连通性问题。在面试中,掌握BFS的基本实现和应用场景,能够帮助你高效解决许多与图或树相关的问题。
85 1
算法系列之搜索算法-广度优先搜索BFS
基于GA遗传算法的斜拉桥静载试验车辆最优布载matlab仿真
本程序基于遗传算法(GA)实现斜拉桥静载试验车辆最优布载的MATLAB仿真,旨在自动化确定车辆位置以满足加载效率ηq(0.95≤ηq≤1.05)的要求,目标是使ηq尽量接近1,同时减少加载车辆数量和布载耗时。程序通过迭代优化计算车辆位置、方向、类型及占用车道等参数,并展示适应度值收敛过程。测试版本为MATLAB2022A,包含核心代码与运行结果展示。优化模型综合考虑车辆总重量、间距及桥梁允许载荷密度等约束条件,确保布载方案科学合理。
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
本程序基于免疫算法实现物流仓储点选址优化,并通过MATLAB 2022A仿真展示结果。核心代码包括收敛曲线绘制、最优派送路线规划及可视化。算法模拟生物免疫系统,通过多样性生成、亲和力评价、选择、克隆、变异和抑制机制,高效搜索最优解。解决了物流仓储点选址这一复杂多目标优化问题,显著提升物流效率与服务质量。附完整无水印运行结果图示。
基于免疫算法的最优物流仓储点选址方案MATLAB仿真
基于GA遗传优化TCN时间卷积神经网络时间序列预测算法matlab仿真
本内容介绍了一种基于遗传算法优化的时间卷积神经网络(TCN)用于时间序列预测的方法。算法运行于 Matlab2022a,完整程序无水印,附带核心代码、中文注释及操作视频。TCN通过因果卷积层与残差连接学习时间序列复杂特征,但其性能依赖超参数设置。遗传算法通过对种群迭代优化,确定最佳超参数组合,提升预测精度。此方法适用于金融、气象等领域,实现更准确可靠的未来趋势预测。

热门文章

最新文章