算法—模拟

目录

替换所有的问号

提莫攻击

[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_891450462 小时前
C++中的职责链模式实战
开发语言·c++·算法
m0_708830962 小时前
C++中的原型模式变体
开发语言·c++·算法
Trouvaille ~2 小时前
【Linux】Linux线程概念与控制(四):glibc源码剖析与实现原理
linux·运维·服务器·c++·操作系统·glibc·线程控制
热爱编程的小刘2 小时前
Lesson02---类与对象(上篇)
开发语言·c++
!停2 小时前
数据结构时间复杂度
c语言·开发语言·算法
探索宇宙真理.2 小时前
AhaChat Messenger WordPress漏洞 | CVE-2025-14316 复现&研究
经验分享·开源·wordpress·安全漏洞
AI科技星2 小时前
电磁光速几何耦合常数 Z‘ 的几何起源、第一性原理推导与多维度验证
人工智能·线性代数·算法·矩阵·数据挖掘
王老师青少年编程2 小时前
2025信奥赛C++提高组csp-s复赛真题及题解:社团招新
c++·真题·csp·信奥赛·csp-s·提高组·复赛
每天要多喝水2 小时前
贪心算法专题Day19
算法·贪心算法