本篇内容我们将学习C++算法的下一个主要算法思想:模拟。
很多人将「模拟算法」误解为最简单的"照着做",从而忽视了其背后蕴含的深刻计算机科学思想------建模。事实上,每一次成功的模拟,都是一次出色的建模过程。
它要求我们首先在脑中或纸上建立一个清晰的、无二义性的逻辑模型,这个模型需要精准地反映题目的所有规则和约束。然后,我们再用编程语言的数据结构(如数组、链表、状态机)和控制流(循环、分支)将这个抽象模型"实例化"。这个过程,与软件工程中的系统设计何其相似!本文将与你一同探讨,如何超越机械的代码翻译,从建模的高度去思考和解决模拟问题,从而提升你的整体编程与设计能力。
接下来我们将就这个专题进行深入的算法学习
相关代码已经上传至作者的个人gitee:CPP 学习代码库: C++代码库新库,旧有C++仓库满员了,喜欢请点个赞谢谢
目录
基本概念
模拟(Simulation)是指通过构建模型来复现现实系统或过程的行为特征,从而进行分析、预测或训练的技术。现代模拟技术已广泛应用于科学研究、工程设计、军事训练和商业决策等多个领域。
核心技术要素
-
建模方法
- 物理建模:基于物理定律构建数学模型
- 数据驱动建模:利用机器学习算法从历史数据中学习系统行为
- 混合建模:结合物理定律与数据驱动方法
-
仿真引擎
- 离散事件仿真
- 连续系统仿真
- 实时仿真系统
-
验证与确认
- 模型验证(Verification):确保模型实现正确
- 模型确认(Validation):确保模型准确反映现实系统
典型应用场景
工业领域
- 制造系统模拟:优化生产流程,预测产能瓶颈
- 产品性能模拟:汽车碰撞测试、飞机气动特性分析
- 工艺过程模拟:化学反应过程仿真
军事领域
- 战场环境模拟:用于战术训练和作战计划评估
- 武器装备模拟:导弹飞行轨迹预测
- 指挥决策模拟:战争推演系统
医疗领域
- 手术模拟训练:使用虚拟现实技术培训外科医生
- 药物作用模拟:预测新药在人体内的代谢过程
- 流行病传播模拟:预测疾病传播趋势
实施步骤
- 明确目标:确定模拟要解决的具体问题
- 系统分析:研究实际系统的关键特性和边界条件
- 模型构建:选择合适的建模方法和工具
- 参数设置:确定模型参数和初始条件
- 仿真运行:执行模拟计算
- 结果分析:验证数据有效性并得出结论
- 优化迭代:根据分析结果改进模型
以上部分建议先在演草纸上模拟流程然后将其转换为代码
发展趋势
- 高性能计算:利用GPU加速和分布式计算处理大规模仿真
- 数字孪生:构建物理实体的虚拟镜像,实现实时交互
- AI增强:结合机器学习提高模拟精度和效率
- 云仿真平台:提供按需使用的仿真服务
- 多学科协同仿真:整合不同领域的模拟系统
1、替换所有的问号

cpp
class Solution {
public:
string modifyString(string s)
{
int n=s.size();
for(int i=0;i<n;i++)
{
if(s[i]=='?')
{
for(char ch='a';ch<='z';ch++)
{
if((i==0||ch!=s[i-1])&&(i==n-1||ch!=s[i+1]))
{
s[i]=ch;
break;
}
}
}
}
return s;
}
};
2、提莫攻击

算法原理:

cpp
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration)
{
int n=timeSeries.size();
int sum=0;
for(int i=0;i<n-1;i++)
{
if(timeSeries[i+1]-timeSeries[i]>=duration)
{
sum+=duration;
}
else
{
sum+=(timeSeries[i+1]-timeSeries[i]);
}
}
sum+=duration;
return sum;
}
};
3、Z字形变换

算法思想:
1、模拟:

代码思路
-
特殊情况处理 :如果行数
numRows
为 1 或者大于等于字符串长度,直接返回原字符串,因为不需要变换。 -
计算周期 :一个完整的 Z 字形周期(向下和斜向上)的长度为
t = 2 * numRows - 2
。 -
计算列数 :根据周期数计算所需的列数,每个周期占用
numRows - 1
列。 -
初始化矩阵 :创建一个
numRows
行c
列的矩阵,所有元素初始化为空字符(ASCII 0)。 -
填充矩阵:遍历字符串中的每个字符,根据当前在周期中的位置决定移动方向(向下或斜向上),并将字符放入矩阵的对应位置。
-
构建结果字符串:按行遍历矩阵,将非空字符拼接成结果字符串
cppclass Solution { public: string convert(string s, int numRows) { int n = s.length(), r = numRows; // 特殊情况处理:如果行数为1或行数超过字符串长度,直接返回原字符串 if (r == 1 || r >= n) { return s; } // 计算一个周期的长度:向下移动r行,斜向上移动r-2行(总移动次数为2r-2) int t = r * 2 - 2; // 计算需要的列数:周期数向上取整乘以每个周期的列数(r-1) // (n + t - 1) / t 是周期数的向上取整 int c = (n + t - 1) / t * (r - 1); // 初始化矩阵:r行c列,所有元素初始化为0(空字符) vector<string> mat(r, string(c, 0)); // 遍历字符串,填充矩阵 // x和y表示当前字符在矩阵中的行和列坐标 for (int i = 0, x = 0, y = 0; i < n; ++i) { mat[x][y] = s[i]; // 将当前字符放入矩阵 // 判断当前在周期中的位置:如果当前索引在一个周期内的位置小于r-1,则向下移动 if (i % t < r - 1) { ++x; // 向下移动,行号增加 } else { --x; // 斜向上移动,行号减少 ++y; // 列号增加 } } // 按行遍历矩阵,将非空字符拼接成结果字符串 string ans; for (auto &row : mat) { for (char ch : row) { if (ch) { // 如果字符不是空(即ASCII值不为0),则添加到结果 ans += ch; } } } return ans; } };
2、找规律

n=1的时候特别处理一下
cpp
class Solution {
public:
string convert(string s, int numRows)
{
//处理边界情况
if(numRows==1) return s;
string ret;
int d=numRows*2-2,n=s.size();
//处理第一行
for(int i=0;i<n;i+=d)
{
ret+=s[i];
}
//中间行
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];
}
}
//处理最后一行
for(int i=numRows-1;i<n;i+=d)
{
ret+=s[i];
}
return ret;
}
};
4、外观数列


算法思路:模拟+双指针
cpp
class Solution {
public:
string countAndSay(int n)
{
string ret="1";
//解释n-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[right]==ret[left]) right++;
tmp+=to_string(right-left)+ret[left];
left=right;
}
ret=tmp;
}
return ret;
}
};
5、数青蛙
算法思想:模拟+哈希表
找前驱字符是否存在于哈希表中。
如果存在在哈希表中--,当前字符++;如果不存在,返回-1
遍历到c的时候找最后一个字符是否在哈希表中。
如果存在让最后一个字符个数--,当前字符++;如果不存在,当前字符++
cpp
class Solution {
public:
int minNumberOfFrogs(string croakOfFrogs)
{
string t="croak";
int n=t.size();
vector<int>hash(n);//数组模拟哈希表
unordered_map<char,int>index;//存储对应下标
for(int i=0;i<n;i++)
index[t[i]]=i;
for(auto& x:croakOfFrogs)
{
if(x=='c')
{
if(hash[n-1]!=0) hash[n-1]--;
hash[0]++;
}
else
{
int i=index[x];
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];
}
};
本期学习内容到这里就结束了,喜欢请点个赞谢谢。