跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

模拟算法专题:替换问号、提莫攻击等 5 题详解

模拟算法是解决此类问题的核心思路。本文涵盖替换问号、提莫攻击、Z 字形变换、外观数列及数青蛙五道经典题目。通过代码实现与逻辑推导,展示如何从边界条件入手,利用周期规律或状态机模型高效求解。重点在于理解题意后的模拟过程优化,避免冗余计算,提升代码可读性与执行效率。

墨染流年发布于 2026/3/15更新于 2026/6/1122 浏览
模拟算法专题:替换问号、提莫攻击等 5 题详解

模拟算法实战:5 道经典题目解析

模拟算法的核心在于还原问题的实际运行过程。通过遍历、状态跟踪或规律推导,将抽象逻辑转化为具体代码。以下精选五道典型题目,涵盖字符串处理、区间计算及状态机模型。

039 替换所有的问号

题目描述: 给定一个字符串 s,其中包含小写字母和问号 ?。要求将所有问号替换为小写字母,使得最终字符串中不存在连续重复的字符。

解题思路

采用贪心策略。从左到右遍历字符串,遇到 ? 时,尝试用 'a' 到 'z' 中的字符进行替换。判断条件只需确保当前字符不与前一个和后一个字符相同即可。由于字母表有 26 个字符,而最多只有两个邻居需要避开,因此总能找到合适的字符(通常 'a', 'b', 'c' 中必有一个可用)。

代码实现

class Solution {
public:
    string modifyString(string s) {
        for (int i = 0; i < s.size(); i++) {
            if (s[i] == '?') {
                // 尝试 a~z 中的字符
                for (char ch = 'a'; ch <= 'z'; ch++) {
                    // 检查是否与前后字符冲突
                    if ((i == 0 || ch != s[i - 1]) && 
                        (i == s.size() - 1 || ch != s[i + 1])) {
                        s[i] = ch;
                        break;
                    }
                }
            }
        }
        return s;
    }
};

工程师手记: 这里不需要真的遍历所有 26 个字母,实际上只要试三个字符就足够覆盖所有情况,但为了逻辑清晰,遍历全量也是 O(26*N),复杂度可接受。关键是边界条件的判断,首尾字符没有邻居,需单独处理。


040 提莫攻击

题目描述: 提莫在时间轴上发起攻击,每次攻击使目标中毒 duration 秒。给定攻击时间序列 timeSeries 和中毒持续时间 duration,计算总中毒时间。

解题思路

这是一个典型的区间合并问题。我们关注相邻两次攻击的时间差:

  1. 如果时间差大于等于 duration,说明上次中毒效果已完全结束,累加完整时长。
  2. 如果时间差小于 duration,说明下次攻击在前次中毒结束前开始,此时只累加时间差部分,避免重复计算重叠区域。 最后别忘了加上最后一次攻击的完整 duration。

代码实现

class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        if (timeSeries.empty()) return 0;
        int ret = 0;
        int n = timeSeries.size();
        
        for (int i = 1; i < n; i++) {
            int x = timeSeries[i] - timeSeries[i - 1];
            if (x >= duration) {
                ret += duration;
            } else {
                ret += x;
            }
        }
        // 最后一次攻击必定贡献完整的 duration
        return ret + duration;
    }
};

041 Z 字形变换

题目描述: 将字符串按照指定行数 numRows 以 Z 字形排列,然后按行读取生成新字符串。

解题思路

观察 Z 字形排列的规律,可以发现数据呈现周期性变化。周期长度 T = 2 * numRows - 2。

  • 第一行和最后一行:字符索引间隔固定为 T。
  • 中间行:每两个字符一组,分别位于当前周期的第 k 位和第 T-k 位。

利用这个数学规律,我们可以直接通过下标访问原字符串,无需构建二维数组,从而优化空间复杂度。

代码实现

class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1) return s;
        
        string ret;
        int d = 2 * numRows - 2;
        int n = s.size();
        
        // 1. 处理第一行
        for (int i = 0; i < n; i += d) ret += s[i];
        
        // 2. 处理中间行
        for (int k = 1; k < numRows - 1; k++) {
            for (int i = k, j = d - k; i < n || j < n; i += d, j += d) {
                if (i < n) ret += s[i];
                if (j < n) ret += s[j];
            }
        }
        
        // 3. 处理最后一行
        for (int i = numRows - 1; i < n; i += d) ret += s[i];
        
        return ret;
    }
};

042 外观数列

题目描述: 给定整数 n,返回外观数列的第 n 项。该数列由上一项的描述生成。

解题思路

这本质上是一个字符串迭代过程。对于每一项,我们需要统计连续相同字符的个数,并将'个数 + 字符'拼接成下一项。 例如:1 -> 11 (1 个 1) -> 21 (2 个 1) -> 1211 (1 个 2, 1 个 1)。 使用双指针 left 和 right 来扫描当前字符串,识别连续段。

代码实现

class Solution {
public:
    string countAndSay(int n) {
        string ret = "1";
        for (int i = 1; i < n; i++) {
            string tmp;
            int len = ret.size();
            for (int left = 0, right = 0; right < len;) {
                while (right < len && ret[left] == ret[right]) right++;
                tmp += to_string(right - left) + ret[left];
                left = right;
            }
            ret = tmp;
        }
        return ret;
    }
};

043 数青蛙

题目描述: 给定字符串 croakOfFrogs,表示多只青蛙发出的叫声混合。求最少需要多少只青蛙才能发出这些叫声。

解题思路

青蛙的叫声顺序是固定的 c -> r -> o -> a -> k。我们可以维护一个哈希表(或数组),记录当前处于每个阶段的青蛙数量。

  • 当遇到 'c':如果有刚叫完 'k' 的青蛙,复用它;否则新增一只青蛙。
  • 当遇到其他字符:必须存在对应的前驱字符状态的青蛙,将其状态后移一位。
  • 遍历结束后,所有青蛙都应回到 'k' 状态,否则输入非法。

代码实现

class Solution {
public:
    int minNumberOfFrogs(string croakOfFrogs) {
        string t = "croak";
        int n = t.size();
        vector<int> hash(n, 0); // 记录各阶段青蛙数量
        unordered_map<char, int> index;
        
        for (int i = 0; i < n; i++) index[t[i]] = i;
        
        for (auto ch : croakOfFrogs) {
            if (ch == 'c') {
                if (hash[n - 1] > 0) hash[n - 1]--;
                hash[0]++;
            } else {
                int i = index[ch];
                if (hash[i - 1] == 0) return -1; // 缺少前驱状态
                hash[i - 1]--;
                hash[i]++;
            }
        }
        
        // 检查是否所有青蛙都完成了叫声
        for (int i = 0; i < n - 1; i++) {
            if (hash[i] != 0) return -1;
        }
        return hash[n - 1];
    }
};

以上五道题虽然场景不同,但核心都在于对流程的精确模拟。掌握这类题目的关键在于拆解状态变化,找到循环或递推的规律,从而写出简洁高效的代码。

目录

  1. 模拟算法实战:5 道经典题目解析
  2. 039 替换所有的问号
  3. 解题思路
  4. 代码实现
  5. 040 提莫攻击
  6. 解题思路
  7. 代码实现
  8. 041 Z 字形变换
  9. 解题思路
  10. 代码实现
  11. 042 外观数列
  12. 解题思路
  13. 代码实现
  14. 043 数青蛙
  15. 解题思路
  16. 代码实现
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于西门子 TIA、PLCSIM Advanced 与 Kepware 的 Fanuc 机器人虚拟仿真调试
  • Roo Code 深度上手指南:API 配置与实战应用
  • Prophet Python 和 R 版本安装配置指南
  • Linux 系统下.run 文件格式解析与使用指南
  • 2021 年信奥赛 C++ 提高组 CSP-S 初赛真题解析:阅读程序第 1 题
  • C++ 类与对象完全解析
  • OpenClaw 接入 QQ 机器人配置指南
  • AI 时代内存需求激增背后的能源、隐私与绿色技术解析
  • AI 工具链基础:Python 机器学习实战指南
  • Python 股票金融数据量化分析实战
  • GitHub Copilot Plan 模式核心优势与使用场景分析
  • Layui 框架中 Unity WebGL Tab 切换黑屏问题的解决方案
  • Soft Actor-Critic (SAC) 算法详解与 PyTorch 实现
  • Lottie-Web 完整技术指南:让动画开发更简单高效
  • Win10 升级后自动弹出 Copilot 窗口?彻底禁用与关闭指南
  • Stable Diffusion 实现人脸一致的技术方案与实践
  • Python Pillow 图像处理与格式转换详解
  • Better Exceptions 完全指南:Python 调试进阶
  • C++ 笔试刷题 Day 18:字符串压缩、TopK 与 01 背包
  • Prompt 编写的日志分析与关键字聚类

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online