模拟篇——算法浮世绘,探寻模拟之境的计算艺术(1)

前言

在算法的繁星之海中,模拟算法如同一片微缩的浮世绘,将现实问题投影为虚拟世界的画卷,通过规则和逻辑逐步还原真实场景。它的灵魂在于以细腻的步骤、真实的推演再现复杂的系统演化,常用于交通流量模拟、粒子运动追踪及社会系统建模等场景。本文将从模拟算法的核心概念、典型案例及应用价值展开,揭示这一领域的独特魅力。

一.模拟算法的核心概念

模拟算法(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;
	}
};

小结

本篇关于模拟算法的讲解就暂告段落啦,希望能对各位佬的学习产生帮助,欢迎各位佬前来支持斧正!!!

相关推荐
冠位观测者2 分钟前
【Leetcode 每日一题 - 扩展】45. 跳跃游戏 II
数据结构·算法·leetcode
因特麦克斯3 分钟前
如何实现序列化和反序列化?如何处理对象的生命周期管理?
c++
Hera_Yc.H10 分钟前
C++之二:类和对象
开发语言·c++
Best_Me0724 分钟前
字母异位词分组-力扣热题100道
算法·leetcode·职场和发展
毒丐31 分钟前
VirtualBox使用教程
java·服务器·c++
2401_8711510737 分钟前
十二月第14讲:使用Python实现两组数据纵向排序
开发语言·python·算法
知新_ROL37 分钟前
通过解调使用正则化相位跟踪技术进行相位解包裹
人工智能·算法·机器学习
dbln1 小时前
贪心算法(二)
算法·贪心算法
葟雪儿1 小时前
海思芯片 交叉编译curl
linux·运维·服务器·开发语言·c++·嵌入式硬件
Aloha_up2 小时前
LeetCode hot100-81
算法·leetcode·职场和发展