前言
在算法的繁星之海中,模拟算法如同一片微缩的浮世绘,将现实问题投影为虚拟世界的画卷,通过规则和逻辑逐步还原真实场景。它的灵魂在于以细腻的步骤、真实的推演再现复杂的系统演化,常用于交通流量模拟、粒子运动追踪及社会系统建模等场景。本文将从模拟算法的核心概念、典型案例及应用价值展开,揭示这一领域的独特魅力。
一.模拟算法的核心概念
模拟算法(Simulation Algorithm)是一类通过构造计算机模型,基于初始条件和演化规则,对现实系统进行仿真与预测的算法。其关键特点包括:
- 基于规则驱动:每一步计算遵循明确的规则。
- 逐步演化:从初始状态开始,逐步推进模拟过程。
- 近似真实:通过迭代逼近真实世界的运行模式。
- 模拟算法通常包括以下步骤:
模型构建:定义系统的状态变量、规则与初始条件。
数据输入:为模拟提供初始参数与边界条件。
迭代执行:按照规则更新系统状态,直至满足终止条件。
结果分析:收集和分析输出数据以解释或预测系统行为。
此处我们主要通过模拟算法的理念,模拟算法题目里的场景要求,求解问题,下面我们将结合具体题目加以分析。
二. 替换所有问号
2.1 题目链接:https://leetcode.cn/problems/replace-all-s-to-avoid-consecutive-repeating-characters/description/
2.2 题目分析:
- 给定字符串,要求把?替换为小写字符
- 替换后,字符串内不能存在连续重复字符
- 题目保证初始情况下不存在连续重复字符
2.3 思路讲解:
模拟该场景。从前往后遍历整个字符串,找到问号之后,就⽤ a ~ z 的每⼀个字符去尝试替换即
可。
注意:
当问号位于左边界时,只需要考虑问号右侧的元素
当问号位于右边界时,只需要考虑问号左侧的元素
2.4 代码实现:
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||s[i-1]!=ch)&&(i==n-1||s[i+1]!=ch))
{
s[i]=ch;
}//尝试替换
}
}
}
return s;
}
};
三. 提莫攻击
3.1 题目链接:https://leetcode.cn/problems/teemo-attacking/description/
3.2 题目分析:
- 题目给出一个数组,每个元素代表在此时攻击
- duration表示每次中毒持续时间
- 如果两次攻击间隔时间小于中毒持续时间,则上次中毒剩余的持续时间不会计算,而是会从新开始计时
- 返回最终中毒总时间
3.3 思路讲解:
模拟 + 分情况讨论。
计算相邻两个时间点的差值:
i. 如果差值⼤于等于中毒时间,说明上次中毒可以持续 duration 秒;
ii. 如果差值⼩于中毒时间,那么上次的中毒只能持续两者的差值。
注意:最后一次攻击的中毒持续时间总是可以直接计算,因为不存在中毒重合情况
3.4 代码实现:
cpp
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration) {
int sum=0;//总致盲时间
int n=timeSeries.size();
for(int i=0;i<n-1;i++)
{
if(timeSeries[i]+duration<timeSeries[i+1])
{
sum+=duration;
}//两次攻击间隔大于致盲时间,则直接加一次致盲持续时间
else
{
sum+=timeSeries[i+1]-timeSeries[i];
}//反之则加间隔时间
}
sum+=duration;//最后一次单独计算
return sum;
}
};
四. N字型变化
4.1 题目链接:https://leetcode.cn/problems/zigzag-conversion/description/
4.2 题目分析:
题目给定一个字符串,之后将其按照类似矩阵的规模N字型排列,要求我们逐行从左到右按顺序读取,返回变化之后的字符串。
4.3 思路讲解:
找规律,⽤ row 代替⾏数,row = 4 时画出的 N 字形如下:
0 2row - 2 4row - 4
1 2row - 3 2row - 1 4row - 5 4row - 3
2 2row-4 2row 4row - 6 4row - 2
3 2row + 1 4row - 1
不难发现,数据是以 2row - 2 为⼀个周期进⾏规律变换的。将所有数替换成⽤周期来表⽰的变量:
第⼀⾏的数是:0, 2row - 2, 4row - 4;
第⼆⾏的数是:1, (2row - 2) - 1, (2row - 2) + 1, (4row - 4) - 1, (4row - 4) + 1;
第三⾏的数是:2, (2row - 2) - 2, (2row - 2) + 2, (4row - 4) - 2, (4row - 4) + 2;
第四⾏的数是:3, (2row - 2) + 3, (4row - 4) + 3。
可以观察到,第⼀⾏、第四⾏为差为 2row - 2 的等差数列;第⼆⾏、第三⾏除了第⼀个数取值为⾏数,每组下标为(2n - 1, 2n)的数围绕(2row - 2)的倍数左右取值。
以此规律,我们可以写出迭代算法。
4.4 代码实现:
cpp
class Solution
{
public:
string convert(string s, int numRows)
{
// 处理边界情况
if (numRows == 1) return s;
string ret;
int d = 2 * numRows - 2, 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;
}
};
小结
本篇关于模拟算法的讲解就暂告段落啦,希望能对各位佬的学习产生帮助,欢迎各位佬前来支持斧正!!!