C++算法专题学习:模拟算法

本篇内容我们将学习C++算法的下一个主要算法思想:模拟。

很多人将「模拟算法」误解为最简单的"照着做",从而忽视了其背后蕴含的深刻计算机科学思想------建模。事实上,每一次成功的模拟,都是一次出色的建模过程。

它要求我们首先在脑中或纸上建立一个清晰的、无二义性的逻辑模型,这个模型需要精准地反映题目的所有规则和约束。然后,我们再用编程语言的数据结构(如数组、链表、状态机)和控制流(循环、分支)将这个抽象模型"实例化"。这个过程,与软件工程中的系统设计何其相似!本文将与你一同探讨,如何超越机械的代码翻译,从建模的高度去思考和解决模拟问题,从而提升你的整体编程与设计能力。

接下来我们将就这个专题进行深入的算法学习

相关代码已经上传至作者的个人gitee:CPP 学习代码库: C++代码库新库,旧有C++仓库满员了,喜欢请点个赞谢谢

目录

基本概念

核心技术要素

典型应用场景

工业领域

军事领域

医疗领域

实施步骤

发展趋势

1、替换所有的问号

2、提莫攻击

3、Z字形变换

1、模拟:

2、找规律

4、外观数列

5、数青蛙​编辑


基本概念

模拟(Simulation)是指通过构建模型来复现现实系统或过程的行为特征,从而进行分析、预测或训练的技术。现代模拟技术已广泛应用于科学研究、工程设计、军事训练和商业决策等多个领域。

核心技术要素

  1. 建模方法

    • 物理建模:基于物理定律构建数学模型
    • 数据驱动建模:利用机器学习算法从历史数据中学习系统行为
    • 混合建模:结合物理定律与数据驱动方法
  2. 仿真引擎

    • 离散事件仿真
    • 连续系统仿真
    • 实时仿真系统
  3. 验证与确认

    • 模型验证(Verification):确保模型实现正确
    • 模型确认(Validation):确保模型准确反映现实系统

典型应用场景

工业领域

  • 制造系统模拟:优化生产流程,预测产能瓶颈
  • 产品性能模拟:汽车碰撞测试、飞机气动特性分析
  • 工艺过程模拟:化学反应过程仿真

军事领域

  • 战场环境模拟:用于战术训练和作战计划评估
  • 武器装备模拟:导弹飞行轨迹预测
  • 指挥决策模拟:战争推演系统

医疗领域

  • 手术模拟训练:使用虚拟现实技术培训外科医生
  • 药物作用模拟:预测新药在人体内的代谢过程
  • 流行病传播模拟:预测疾病传播趋势

实施步骤

  1. 明确目标:确定模拟要解决的具体问题
  2. 系统分析:研究实际系统的关键特性和边界条件
  3. 模型构建:选择合适的建模方法和工具
  4. 参数设置:确定模型参数和初始条件
  5. 仿真运行:执行模拟计算
  6. 结果分析:验证数据有效性并得出结论
  7. 优化迭代:根据分析结果改进模型

以上部分建议先在演草纸上模拟流程然后将其转换为代码

发展趋势

  1. 高性能计算:利用GPU加速和分布式计算处理大规模仿真
  2. 数字孪生:构建物理实体的虚拟镜像,实现实时交互
  3. AI增强:结合机器学习提高模拟精度和效率
  4. 云仿真平台:提供按需使用的仿真服务
  5. 多学科协同仿真:整合不同领域的模拟系统

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、模拟:

代码思路

  1. 特殊情况处理 :如果行数 numRows 为 1 或者大于等于字符串长度,直接返回原字符串,因为不需要变换。

  2. 计算周期 :一个完整的 Z 字形周期(向下和斜向上)的长度为 t = 2 * numRows - 2

  3. 计算列数 :根据周期数计算所需的列数,每个周期占用 numRows - 1 列。

  4. 初始化矩阵 :创建一个 numRowsc 列的矩阵,所有元素初始化为空字符(ASCII 0)。

  5. 填充矩阵:遍历字符串中的每个字符,根据当前在周期中的位置决定移动方向(向下或斜向上),并将字符放入矩阵的对应位置。

  6. 构建结果字符串:按行遍历矩阵,将非空字符拼接成结果字符串

    cpp 复制代码
    class 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];
        
    }
};

本期学习内容到这里就结束了,喜欢请点个赞谢谢。

相关推荐
麦子邪4 小时前
C语言中奇技淫巧07-使用GCC栈保护选项检测程序栈溢出
linux·c语言·开发语言
苏言の狗5 小时前
A*(Astar)算法详解与应用
c语言·c++·算法
我认不到你5 小时前
JVM分析(OOM、死锁、死循环)(JProfiler、arthas、jdk调优工具(命令行))
java·linux·开发语言·jvm·spring boot
assibe5 小时前
cmake基本语法结构
数据库·c++·cmake
扶尔魔ocy5 小时前
【QT特性技术讲解】QPrinter、QPdf
开发语言·qt
李铁柱的5 小时前
数值分析——误差的来源与分类、误差的基本概念(绝对误差、相对误差、有效数字)
人工智能·算法·分类·数据挖掘
悠哉悠哉愿意5 小时前
【数学建模学习笔记】异常值处理
笔记·学习·数学建模
君鼎5 小时前
More Effective C++ 条款26:限制某个类所能产生的对象数量
c++
ajassi20005 小时前
开源 C++ QT Widget 开发(十一)进程间通信--Windows 窗口通信
linux·c++·windows·qt·开源