编程艺术::交替字符串 C++语言

题目和分析来自于https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/05.04.md


题目描述

输入三个字符串s1、s2和s3,判断第三个字符串s3是否由前两个字符串s1和s2交错而成,即不改变s1和s2中各个字符原有的相对顺序,例如当s1 = “aabcc”,s2 = “dbbca”,s3 = “aadbbcbcac”时,则输出true,但如果s3=“accabdbbca”,则输出false。



分析

按照原文的分析,考察的是动态规划的知识。

不过原文里的代码,我看着有点奇怪,感觉是错的。

我试了试,dp矩阵打印出来确实是错的。


下面是我改写的,dp矩阵的第0行,还有第0列,都是单独拿出来初始化的,dp[ii][0] = true 含义是string s1[0...ii-1] 在string s2为空的情况下,和string s3[0...ii-1]相等;

同理可得dp[0][jj]的含义。


#include <string>

#include <iostream>
 
using namespace std;
 
bool isInterleave(string &s1, string &s2, string &s3)
{
    int len1 = s1.length();
    int len2 = s2.length();
    int len3 = s3.length();
 
    if (len1 + len2 != len3)
    {
        return false;
    }
 
    if (0 == len1)
    {
        return (s2 == s3) ? true : false;
    }
 
    if (0 == len2)
    {
        return (s1 == s3) ? true : false;
    }
 
    // allocating memory to store middle values
    // we need a bias to get started
 
    bool ** dp = new bool*[len1+1];
    for (int ii = 0; ii < len1+1; ++ii)
    {
       dp[ii] = new bool [len2+1];
    }
 
 
    // dp[ii][jj]== true means that
    // s1[0...ii-1] and s2[0...jj-1] forming s3[0...(ii+jj-1)] is true
    // dp[0][0] means two null string form a null string, which is true
    dp[0][0] = true;
 
    for (int ii = 1; ii < len1+1; ++ii)
    {
 
        dp[ii][0] = (s1.substr(0,ii) == s3.substr(0,ii)) ? true : false;
    }
 
    for (int jj = 1; jj < len2+1; ++jj)
    {
        dp[0][jj] = (s2.substr(0,jj) == s3.substr(0,jj)) ? true : false;
    }
 
    for (int ii = 1; ii < len1+1; ++ii)
    {
        for (int jj = 1; jj < len2+1; ++jj)
        {
            if (  (dp[ii-1][jj] && s1[ii - 1] == s3[ii+jj-1]) ||
                  (dp[ii][jj-1] && s2[jj - 1] == s3[ii+jj-1]) )
            {
                dp[ii][jj] = true;
            }else
            {
                dp[ii][jj] = false;
            }
        }
    }
 
//    for (int ii = 0; ii < len1+1; ++ii)
//    {
//        for (int jj = 0; jj < len2+1; ++jj)
//        {
//            //check char s3[ii+jj-1]
 
//            if (dp[ii][jj] ||
//                    ((ii - 1 > 0) && dp[ii-1][jj] && s1[ii - 1] == s3[ii+jj-1]) ||
//                    ((jj - 1 > 0) && dp[ii][jj-1] && s2[jj - 1] == s3[ii+jj-1]) )
//            {
//                dp[ii][jj] = true;
//            }else
//            {
//                dp[ii][jj] = false;
//            }
//        }
//    }
    cout << "dp matrix:" << endl;
    for (int ii = 0; ii < len1 + 1; ++ii)
    {
        for (int jj = 0; jj < len2 + 1; ++jj)
        {
            cout << dp[ii][jj] << " ";
        }
        cout << endl;
    }
 
    bool result = dp[len1][len2];
 
    for (int ii = 0; ii < len2+1; ++ii)
    {
       delete [] dp[ii];
    }
    delete [] dp;
 
    return result;
 
}
 
int main()
{
    string s1 = "aabcce", s2 = "dbbca";
    string s3 = "aadbbcbcace";
 
    if (isInterleave(s1, s2, s3))
    {
        cout << "yes" << endl;
    }else
    {
        cout << "no" << endl;
    }
}
 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
非常优秀的C++教材,并且附有源码。 目 录 第1章 C++的功能 1 1.1 简洁而丰富的语法 1 1.2 功能强大的库 2 1.3 STL 2 1.4 程序员控制一切 3 1.5 细节控制 3 1.6 运算符重载 3 1.7 一种简洁精练的对象模型 4 1.8 C++发展史 4 第2章 简单的C++垃圾回收器 5 2.1 两种内存管理方法的比较 5 2.1.1 手工内存管理的优缺点 6 2.1.2 垃圾回收的优缺点 6 2.1.3 两种方法都可以使用 7 2.2 在C++中创建垃圾回收器 7 2.3 选择垃圾回收的算法 8 2.3.1 引用计数 9 2.3.2 标记并清除 9 2.3.3 复制 9 2.3.4 采用哪种算法 9 2.3.5 实现垃圾回收器 10 2.3.6 是否使用多线程 10 2.3.7 何时回收垃圾 10 2.3.8 关于auto_ptr 11 2.4 一个简单的C++垃圾回收器 11 2.5 详细讨论GCPtr 23 2.5.1 GCPtr的数据成员 23 2.5.2 函数findPtrInfo() 24 2.5.3 GCIterator typedef 25 2.5.4 GCPtr的构造函数 25 2.5.5 GCPtr的析构函数 26 2.5.6 回收垃圾函数collect() 26 2.5.7 重载赋值运算符 28 2.5.8 GCPtr的复制构造函数 30 2.5.9 指针运算符和转换函数 30 2.5.10 begin()和end()函数 32 2.5.11 shutdown()函数 32 2.5.12 两个实用函数 33 2.6 GCInfo 33 2.7 Iter 34 2.8 如何使用GCPtr 36 2.8.1 处理分配异常 37 2.8.2 一个更有趣的示例 38 2.8.3 对象的分配和丢弃 40 2.8.4 分配数组 41 2.8.5 使用具有类类型的GCPtr 43 2.8.6 一个比较大的演示程序 45 2.8.7 加载测试 51 2.8.8 一些限制 53 2.9 试着完成下面的任务 53 第3章 C++中的多线程 54 3.1 什么是多线程 54 3.2 为什么C++没有内建支持多线程 55 3.3 选用什么样的操作系统和编译器 56 3.4 Windows线程函数概述 56 3.4.1 线程的创建和终止 56 3.4.2 Visual C++对CreateThread()和ExitThread()的替换 57 3.4.3 线程的挂起和恢复 58 3.4.4 改变线程的优先级 59 3.4.5 获取主线程的句柄 60 3.4.6 同步 60 3.5 创建线程控制面板 63 3.5.1 线程控制面板 64 3.5.2 线程控制面板的详细分析 68 3.5.3 控制面板的演示 74 3.6 一个多线程的垃圾回收器 78 3.6.1 附加的成员变量 79 3.6.2 多线程的GCPtr构造函数 79 3.6.3 TimeOutExc异常 81 3.6.4 多线程的GCPtr析构函数 81 3.6.5 gc()函数 82 3.6.6 isRunning()函数 82 3.6.7 gclist的同步访问 83 3.6.8 其他两个改变 83 3.6.9 完整的多线程垃圾回收器 83 3.6.10 多线程垃圾回收器的使用 95 3.7 试着完成下面的任务 97 第4章 C++的扩展 98 4.1 为什么使用译码器 98 4.2 实验性的关键字 99 4.2.1 foreach循环 99 4.2.2 cases语句 100 4.2.3 typeof 运算符 101 4.2.4 repeat/until循环 102 4.3 试验C++新特性的译码器 102 4.4 使用译码器 111 4.5 译码器的运行方式 112 4.5.1 全局声明 112 4.5.2 main()函数 112 4.5.3 gettoken()和skipspaces()函数 114 4.5.4 转换foreach循环 117 4.5.5 转换cases语句 119 4.5.6 转换typeof运算符 121 4.5.7 转换repeat/until循环 122 4.6 演示程序 124 4.7 尝试完成以下任务 130 第5章 Internet文件下载工具 131 5.1 WinINet库 131 5.2 文件下载工具子系统 132 5.2.1 操作的一般理论 137 5.2.2 download()函数 137 5.2.3 ishttp()函数 142 5.2.4 httpverOK()函数 142 5.2.5 getfname()函数 143 5.2.6 openfile()函数 143 5.2.7 update()函数 144 5.3 Download头文件 145 5.4 文件下载工具的演示 145 5.5 基于GUI的下载工具 147 5.5.1 WinDL代码 147 5.5.2 WinDL的运行方式 152 5.6 尝试完成以下任务 153 第6章 使用C++的财务计算 154 6.1 计算贷款的定期偿还 154 6.2 计算投资的预期价值 156 6.3 计算为了获得预期的价值所需的原始投资 157 6.4 为了获得预期的养老金所需的原始投资 159 6.5 计算给定投资所能得到的养老金的最大值 160 6.6 计算贷款余额 162 6.7 尝试完成以下任务 163 第7章 基于AI的问题求解 164 7.1 表示法和术语 164 7.2 组合爆炸 165 7.3 搜索方法 167 7.4 需要解决的问题 167 7.5 FlightInfo结构和Search类 169 7.6 深度优先搜索 171 7.6.1 match()函数 176 7.6.2 find()函数 177 7.6.3 findroute()函数 177 7.6.4 显示路线 179 7.6.5 深度优先搜索分析 179 7.7 广度优先搜索 179 7.8 添加启发信息 182 7.8.1 爬山搜索法 183 7.8.2 爬山法分析 189 7.9 最低成本搜索 189 7.10 寻找多解 190 7.10.1 路径删除 191 7.10.2 节点删除 192 7.11 寻找“最优”解决方案 198 7.12 回到丢失钥匙的问题 204 7.13 尝试完成以下任务 207 第8章 定制STL容器 208 8.1 STL的简要回顾 208 8.1.1 容器 209 8.1.2 算法 209 8.1.3 迭代器 209 8.2 其他的STL实体 209 8.3 定制容器的要求 210 8.3.1 一般要求 210 8.3.2 序列式容器的其他要求 211 8.3.3 关联式容器的要求 211 8.4 创建范围可选的动态数组容器 212 8.4.1 RangeArray的运行方式 212 8.4.2 完整的RangeArray类 213 8.4.3 详细讨论RangeArray类 224 8.4.4 一些RangeArray示例程序 235 8.4.5 尝试完成以下任务 245 第9章 Mini C++解释程序 246 9.1 解释程序和编译器 246 9.2 Mini C++纵览 247 9.3 Mini C++说明 247 9.4 非正式的C++理论 249 9.4.1 C++表达式 250 9.4.2 定义表达式 250 9.5 表达式解析器 252 9.5.1 解析器代码 252 9.5.2 分解源代码 264 9.5.3 显示语法错误 270 9.5.4 表达式求值 271 9.6 Mini C++解释程序 272 9.6.1 main()函数 291 9.6.2 解释程序的预扫描程序 292 9.6.3 interp()函数 295 9.6.4 处理局部变量 297 9.6.5 调用用户自定义的函数 299 9.6.6 给变量赋值 300 9.6.7 执行if语句 302 9.6.8 switch语句和break语句 304 9.6.9 处理while循环 306 9.6.10 处理do-while循环 307 9.6.11 for循环 308 9.6.12 处理cin和cout语句 309 9.7 Mini C++的库函数 311 9.8 mccommon.h头文件 313 9.9 编译并链接Mini C++解释程序 315 9.10 演示Mini C++ 315 9.11 改进Mini C++ 323 9.12 扩展Mini C++ 324 9.12.1 添加新的C++特性 324 9.12.2 添加辅助特性 325

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值