C++ 模拟 力扣1576. 替换所有的问号 题解 每日一题
文章目录
- 模拟算法
- 模拟到底是什么?—— 算法界的“按图索骥”
- 解题思路
- 模拟算法的意义:别小看“照着做”,它是算法的“地基”
- 模拟算法做题策略:先保证“做对”,再追求“做好”
- 题目描述
- 为什么这道题值得练?
- 算法原理
- 代码实现时的细节
- 核心问题:怎么判断字母能不能用?
- 代码实现
- 总结
- 下题预告
模拟算法
模拟到底是什么?—— 算法界的“按图索骥”
提起算法,很多人第一反应是“动态规划的复杂状态”“贪心的精妙选择”,但模拟算法偏偏是个“异类”——它不玩花活,核心就俩字:照着来。
你可以把它理解成“按食谱做饭”:题目已经把“要做什么、步骤是什么”明明白白告诉你了,比如“先切菜、再倒油、最后炒5分钟”,你的任务不是琢磨“能不能换个菜谱”,而是把“切菜要切多碎、油热到什么程度”这些细节落地成代码。
所以模拟算法的“简单”,是思路上的“好想”——只要读明白题,脑子里基本就有流程了;但它的“难”,藏在代码的“落地能力”里:比如边界有没有漏、细节有没有错、逻辑有没有绕晕 😵。
解题思路
很多朋友也包括我做模拟题的经常会出现的误区:读题的时候觉得“哦这简单”,直接上手写代码,结果写着写着就卡壳——要么漏了某个条件,要么处理错了边界,往往最后还是要落实在纸面上,步入最开始就一步一步写出来。
其实模拟题的解题思路就藏在题目描述里,但一定要加一步:把思路“画”出来。不管是在草稿纸上写流程,还是在电脑上用注释列步骤,哪怕是像小学生做题一样“逐句翻译”题目,都能帮你避开80%的坑。
举个例子:如果题目说“把字符串里的问号换成字母,不能和前后重复”,别要光想“换a就行吧?”,而是要写清楚:
- 遍历字符串,遇到问号才处理🚩;
- 处理问号时,得看左边的字符是什么(如果有的话) 👈;
- 还要看右边的字符是什么(如果有的话)👉;
- 选一个既不等于左边、也不等于右边的字母填上✅。
这一步看似“麻烦”,但写代码时会顺风顺水——因为你相当于把“脑子里的模糊想法”变成了“清晰的执行步骤”💡。
模拟算法的意义:别小看“照着做”,它是算法的“地基”
我刚学算法时,也偷偷质疑过:“模拟这玩意儿也算算法?不就是把题目翻译成代码吗?” 🤔
直到后来做了更难的题才明白:所有复杂算法,本质都是“更高级的模拟”。比如动态规划,是在模拟“状态转移的过程”;贪心算法,是在模拟“每一步选最优的决策”;甚至图论里的BFS,也是在模拟“一层一层遍历节点的过程”。
如果连“简单题的模拟”都写得磕磕绊绊,遇到“需要拆解、抽象、优化的复杂模拟题”只会更懵。比如有些模拟题需要你先选合适的数据结构(用数组还是队列?),再处理海量边界(比如时间格式转换里的“月份有没有31天”“闰年2月多一天”),还要优化效率(比如避免双重循环超时)——这些能力,都是从“简单模拟”里练出来的。
所以别觉得模拟“low”,它是帮你打通“算法思路”和“代码实现”的关键一步。
模拟算法做题策略:先保证“做对”,再追求“做好”
模拟题在笔试里很常见,尤其是作为“热身题”或“中档题”出现。这时候的核心目标是:在最短时间内AC,别纠结“代码好不好看”。
分享我自己的做题流程,亲测高效:
- 读题划重点:用笔画出题目里的“必须满足的条件”(比如“不能连续重复”“不能修改非问号字符”)和“边界情况”(比如“字符串长度为1”“问号在开头/结尾”);
- 草稿纸模拟示例:拿题目给的示例(比如示例1的“?zs”),在纸上一步步走流程——比如“第一个字符是问号,右边是z,所以填a就行”;
- 写代码先搭框架:先写最核心的逻辑(比如遍历字符串、遇到问号进入循环),再补细节(比如判断左右字符);
- 测试边界用例:写完后别直接提交,自己造几个极端情况测一测——比如输入是“?”(只有一个问号)、输入是“???”(全是问号)、输入是“a?b?c”(问号在中间),确保这些情况都能跑对。
记住:笔试里“AC”比“代码优雅”重要一万倍——哪怕你用了三层循环(只要不超时),只要能过所有测试用例,就是好代码👍。
题目描述
题目链接:力扣1576. 替换所有的问号
题目描述:
示例 1:
输入:s = “?zs”
输出:“azs”
解释:该示例共有 25 种解决方案,从 “azs” 到 “yzs” 都是符合题目要求的。只有 “z” 是无效的修改,因为字符串 “zzs” 中有连续重复的两个 ‘z’ 。
示例 2:
输入:s = “ubv?w”
输出:“ubvaw”
解释:该示例共有 24 种解决方案,只有替换成 “v” 和 “w” 不符合题目要求。因为 “ubvvw” 和 “ubvww” 都包含连续重复的字符。
提示:
1 <= s.length <= 100
s 仅包含小写英文字母和 ‘?’ 字符
为什么这道题值得练?
这道题是模拟题的“标准模板”,它完美覆盖了模拟题的核心考点:常规逻辑处理 + 边界情况判断。既不用我们想复杂的算法,又能帮我们练“代码细节把控”,还有就是这道题算是奖励题嘻嘻😄。
而且它的场景很贴近笔试:难度不高,但容易因为漏细节翻车(比如忘了处理“问号在开头”的情况),练会这道题,能帮你避开很多同类坑。
算法原理
我们直接来一步一步的模拟
1.一般情况(示例2为例,问号在中间)
如图所示👇:
2.边界情况(问号在开头/结尾)
在正常的模拟的时候我们要注意自己去找一找边界情况,有的时候题目的示例不会给你边界情况,即?在字符串第一个和最后一个的时候(以示例1为例)
如下图👇:
同理最右侧也相同
代码实现时的细节
我们在做模拟时的追求是,用最少的代码,实现最快的代码,其实这也是我们学习算法的追求。
所以这道题的几个细节单独提炼出来分析,在做题的时候这一部也很重要。
核心问题:怎么判断字母能不能用?
首先我们模拟填入字母一定是按照a~z的顺序填入的无非就是一个循环,但是在判断左右这里,我们是通过什么方法来又省时间又省空间呢?
我真实的思路是用哈希表,最开始是想用if判断写但是因为没有将所有的条件写出来(脑子里面想的是又要处理边界情况,又要判断前面又要判断后面的)下意识就直接用了哈希……
在实现出来之后发现代码又长又臭❌
- 为了存两个可能存在的字符,特意开了个哈希表,纯属浪费空间;
- 插入哈希表、判断是否存在,这些操作虽然简单,但完全没必要;
- 本质上就是“为了处理两个条件,却用了一个复杂的数据结构”。
真的是简单问题复杂做。
分析判断条件有哪些
-
关于左边:
- 如果是第一个字符(i=0),左边没有字符 → 不用判断左边;
- 否则,必须保证新字母 ≠ 左边的字符(j != s[i-1])。
-
关于右边:
- 如果是最后一个字符(i = s.size()-1),右边没有字符 → 不用判断右边;
- 否则,必须保证新字母 ≠ 右边的字符(j != s[i+1])。
列出来之后突然发现:这不就是四个简单的条件吗?而且可以用“或(||)”和“与(&&)”组合起来!
左边的判断可以写成:i == 0 || j != s[i-1]
(要么是开头,要么不等于左边);
右边的判断可以写成:i == s.size()-1 || j != s[i+1]
(要么是结尾,要么不等于右边);
两个条件都满足,就可以用这个字母:
((i == 0 || j != s[i - 1]) && (i == s.size() - 1 || j != s[i+1]))
就这么这么一个简单的判断,完全能替代哈希表的功能,还更高效、更简洁。✨
==反思:为什么会绕远路?==🤯
后来我想了想,当时之所以会想到用哈希表,其实是因为:
- 面对“多种情况”时,第一反应是“用工具去包容所有情况”,而不是“用逻辑去简化条件”;
- 没耐心先拆解问题,总想着“赶紧写代码试错”,结果越走越偏。
所以做模拟题时,真的别急着写代码——先在纸上把逻辑理清楚,往往能少走很多弯路。就像这道题,看似复杂的条件,其实用一个if判断就能解决。
代码实现
class Solution {
public:string modifyString(string s) {// 遍历字符串的每个字符for(int i = 0; i < s.size(); i++){// 只处理问号if(s[i] == '?'){// 从a到z试字母,找到能用的就填for(char j = 'a'; j <= 'z'; j++){// 核心判断:既不跟左边重复,也不跟右边重复(处理边界)if((i == 0 || j != s[i - 1]) && (i == s.size() - 1 || j != s[i + 1])){s[i] = j; // 填上能用的字母break; // 找到就退出,不用再试其他字母}}}}return s; // 返回处理后的字符串}
};
这段代码的优点:
- 没有多余的数据结构(比如哈希表),空间复杂度O(1);
- 判断条件简洁,一眼能看懂;
- 从a开始试字母,保证能找到答案(题目说答案存在)。
总结
做模拟题,别追求“炫技”,记住三个关键词:
- 画流程 🖍️:别光靠脑子想,把步骤写在纸上/注释里;
- 抓边界 🚫:注意“开头/结尾”“空值”“极值”这些容易漏的情况;
- 简判断 ✂️:能用一个条件搞定的,别拆成多个if-else,既省代码又不容易错。
练会这些,你面对大部分模拟题都能游刃有余。
下题预告
下一篇我们来练一道“稍微复杂点的模拟题”——提莫攻击🎮。玩英雄联盟的朋友命该很熟悉这道题,它需要我们先“理解中毒时间的计算逻辑”,再转化成代码,能帮我们进一步提升“拆解问题”的能力,感兴趣的朋友可以先去看看题目哦~
力扣 495. 提莫攻击
如果这篇内容对你有帮助,别忘了 点赞👍 + 收藏⭐ + 关注👀 哦!
有问题欢迎在评论区留言,我会认真思考并及时回复!