算法—模拟

目录

替换所有的问号

提莫攻击

[Z 字形变换](#Z 字形变换)

外观数列

数青蛙


注意: 模拟算法其实就是将题目描述的流程转换为代码,当根据题目流程转换后时间复杂度或者空间复杂度特别高时通常可以通过找规律来优化代码。

替换所有的问号

**思路:**遍历字符串,碰到 '?' 就进行替换,替换时从 a~z 尝试即可,只要不和前后的字符重复即可,但是需要考虑一些特殊情况,第一个字符如果是 '?' 替换时就不需要比前面的字符了,最后一个字符如果是 '?' 替换时就不需要比后面的字符了。

代码:

cpp 复制代码
class Solution {
public:
    string modifyString(string s) {
        for(int i = 0; i < s.size(); i++){
            if(s[i] == '?'){
                for(int j = 0; j < 26; j++){
                    if(i - 1 >= 0)
                        if(s[i - 1] == 'a' + j)
                            continue;

                    if(i + 1 < s.size())
                        if(s[i + 1] == 'a' + j)
                            continue;

                    s[i] = 'a' + j;
                    break;
                }
            }
        }

        return s;
    }
};

提莫攻击

**思路:**当两次攻击时间的差值 >= duration 时,说明第二次攻击是在第一次中毒状态结束后攻击的,此时第一次攻击的中毒时间按 duration 算;当两次攻击时间的差值 < duration 时,说明第二次攻击是在第一次中毒状态还没结束就攻击了,此时第一次攻击中毒的持续时间只需要按两次攻击的时间差算就行。以此类推,直到最后一次攻击,因为最后一次攻击持续时间一定是 duration,所以最后一次攻击不需要像前面那样比较,直接向结果中加 duration 即可。

代码:

cpp 复制代码
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ret = 0;
        for(int i = 0; i < timeSeries.size(); i++){
            if(i == timeSeries.size() - 1 || timeSeries[i + 1] - timeSeries[i] >= duration)
                ret += duration;
            else 
                ret += timeSeries[i + 1] - timeSeries[i];
        }

        return ret;
    }
};

Z 字形变换

思路: 这道题主要是找给定的行数和字符按照Z形排列后的下标之间的关系,然后根据这个关系,在遍历字符串的时候直接依次取出相应的字符拼接成结果字符串。具体如图:

代码:

cpp 复制代码
class Solution 
{
public:
    string convert(string s, int numRows) 
    {
        if(numRows == 1)
            return s;

        string ret;
        int n = s.size();
        int d = numRows * 2  - 2;

        for(int i = 0; i < n; i += d)
        {
            ret += s[i];
        }
        for(int i = 1; i < numRows - 1; i++)
        {
            for(int k = i, j = d - k; k < n || j < n; k += d, j += d)
            {
                if(k < n)
                    ret += s[k];
                if(j < n)
                    ret += s[j];
            }
        }
        for(int i = numRows - 1; i < n; i += d)
        {
            ret += s[i];
        }

        return ret;
    }
};

外观数列

**思路:**还是模拟的思想,直接将题目描述的过程转化成代码,另外还需要使用双指针来配合模拟的过程,方便确定连续的相同数字的区间。具体如图:

  • left 指针指向的数字就是当前需要描述的数字。
  • right - left 就是当前要描述的数字的个数。
  • 当前区间描述完让 left 移动到 right 位置,继续找下一个区间即可。

代码:

cpp 复制代码
class Solution {
public:
    string countAndSay(int n) {
        string ret = "1";
        for(int i = 1; i < n; i++){
            int left = 0;
            int right = 0;
            string tmp;
            while(right < ret.size()){
                while(ret[left] == ret[right])
                    right++;
                tmp += (right - left) + '0';
                tmp += ret[left];
                left = right;
            }
            ret = tmp;
        }

        return ret;
    }
};

数青蛙

**思路:**创建一个哈希表,存储 croak 中每个字符和对应出现次数的映射关系,遍历字符串,当前遍历的字符是 roak 中的任意一个时,找一下哈希表中当前字符的前驱字符是否在哈希表中存在,如果存在,说明有青蛙叫了上一个字符,让这个青蛙接下来叫这个字符,即前面的字符个数自减 1,当前字符数量自加 1,如果前面字符不存在,说明字符串不是有效组合,因为题目要求字符串必须由若干有效的croak组成,而当前字符的前驱字符不存在,说明当前遍历的这个 croak 是不完整的,返回 -1。如果当前遍历的字符是 c,找 k 对应次数是否大于 0,如果大于零,让 k 自减 1,c 对应个数自加 1,否则只让 c 的个数自加 1即可,因为题目要求最少的青蛙,叫到 k 的青蛙已经叫完了完整的一声,所以当遇到 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 ch : croakOfFrogs)
        {
            if(ch == 'c')
            {
                if(hash[n - 1] != 0)
                    hash[n - 1]--;
                hash[0]++;
            }
            else
            {
                int i = index[ch];
                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];
    }
};
相关推荐
2401_892070981 天前
【Linux C++ 日志系统实战】LogFile 日志文件管理核心:滚动策略、线程安全与方法全解析
linux·c++·日志系统·日志滚动
yuzhuanhei1 天前
Visual Studio 配置C++opencv
c++·学习·visual studio
小O的算法实验室1 天前
2026年ASOC,基于深度强化学习的无人机三维复杂环境分层自适应导航规划方法,深度解析+性能实测
算法·无人机·论文复现·智能算法·智能算法改进
其实秋天的枫1 天前
【2026年最新】驾考科目一考试题库2309道电子版pdf
经验分享·pdf
一轮弯弯的明月1 天前
贝尔数求集合划分方案总数
java·笔记·蓝桥杯·学习心得
不爱吃炸鸡柳1 天前
C++ STL list 超详细解析:从接口使用到模拟实现
开发语言·c++·list
十五年专注C++开发1 天前
RTTR: 一款MIT 协议开源的 C++ 运行时反射库
开发语言·c++·反射
‎ദ്ദിᵔ.˛.ᵔ₎1 天前
STL 栈 队列
开发语言·c++
2401_892070981 天前
【Linux C++ 日志系统实战】高性能文件写入 AppendFile 核心方法解析
linux·c++·日志系统·文件写对象
郭涤生1 天前
STL vector 扩容机制与自定义内存分配器设计分析
c++·算法