优选算法【专题六_模拟】

目录

1、1676.替换所有的问号

2、495.提莫攻击

3、6.Z字形变换

4、1419.数青蛙

5、38.外观数列


模拟算法--->"比葫芦画瓢"

特点是:思路简单,主要考察将思路转化为代码的能力。

第一步:模拟算法流程(一定要在演草纸上过一遍流程)

第二步:把流程转化为代码

1、1676.替换所有的问号

cpp 复制代码
class Solution 
{
public:
    string modifyString(string s) 
    {
        int n = s.size();
        for(int i = 0; i < n; i++)
        {
            if(s[i] == '?')
            {
                for(int 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;
    }
};

【遇到?将?替换为前面位置和后面位置都没有的字符,这样就不会出现连续重复的字符串】我们在遇到?之后,需要找一个字符放进来,遍历a到z,这个字符不能等于?前面的字符,也不能等于?后面的字符。

if( (i== 0 || ch != s[i - 1] ) && (i == n-1 || ch != s[i + 1]) ) ?在最前面出现不用判断前面的,在最后面出现不用判断后面的

2、495.提莫攻击

cpp 复制代码
class Solution 
{
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) 
    {
        int ret = 0;
        for(int i = 1; i < timeSeries.size(); i++)
        {
            int x = timeSeries[i] - timeSeries[i - 1];
            if(x >= duration) //间隔大于中毒时间,就要加上全部的中毒时间
            ret += duration;
            else ret += x;//间隔小于中毒时间,就加上间隔
        }
        return ret + duration; //最后一个攻击点的执行时间肯定是中毒持续时间,所以最后还要加上。
    }
};

3、6.Z字形变换

解法一:模拟

通过一个矩阵,矩阵行数为n,矩阵列数可以设置为字符串的长度。但是这样时间复杂度太大了。

解法二:对模拟算法进行优化---------找规律

根据原始的模拟结果来反推规律!!! 百分之99的模拟题都要通过找规律来解决。

第一行:每个元素下标相隔k 在for循环中直接 i+=k (元素下标从0开始)

中间行:第一个元素是,下标为j = 1的元素,第二个是下标 为 k-j 第三个是j+k,第四个是 k-j+k

第五个是j+k+k 第六个是k-j+k+k

所以就需要双层循环,第一层从j行开始(第二层)往后每次增加k个(两个元素都一样); 然后就从j+1,到了下一行,往后每次增加k

cpp 复制代码
class Solution 
{
public:
    string convert(string s, int numRows) 
    {
        if(numRows == 1) return s;//处理边界情况,当只有一个元素的时候,算出来的k=0,那么这样在后面的for循环里面,就会死循环
        string ret;//输出字符串
        int k = (2 * numRows) - 2;//方差k
        int n = s.size();
        //1、处理第一行
        for(int i = 0; i < n; i += k)//由规律可以得知,第一个元素和第二个之间的下标差为k,所以,直接从下标0开始遍历数组,每次增加k,得到下一个数组。
        {
            ret += s[i];//放进要输出的字符串中。第一行的字符,是需要每次往后移动k个的 直接用for循环进行控制
        }
        //2、处理中间行--中间行可能会有很多行,所以先要枚举中间行,---中间行的元素根据规律是两个两个一组的。
        for(int j = 1; j < numRows - 1; j++)//枚举中间的行
        {
            for(int i = j,d = k - j; i < n || d < n; i += k, d += k)//两个元素第一个从这一行开始,第二个是k-j
            {
                if(i < n) ret += s[i];//源字符串中的第i个(下标为i)--可以通过找第i行的,i就是元素下标,i+=k 就是第三个元素
                if(d < n) ret += s[d];//源字符串的下标为d的元素,d=k-j,那么d+=k 就是第四个元素
            }
        }
        for(int i = numRows - 1; i < s.size(); i += k)
        {
            ret += s[i];//下标刚好等于行数-1,每次向后移动k
        }   
        return ret;
    }
};

ret += s[i]:就可以把字符放到字符串中。

4、1419.数青蛙

统计前面字符出现的情况

青蛙需要叫出croak就算叫了一声,并且叫声必须按顺序出现。

所以,我们设一个哈希表

指向c的时候,c+1,指向r的时候,看哈希表里面有没有c,有c就给r+1, c-1,当再次指向c的时候,发现哈希表里面没有c就给c+1,然后走到o就要看前面有没有r,有r就将o+1,r-1.直到走到k。两个都走到k的时候k=2,当再次出现c的时候,此时就让k-1,c+1,就不需要第三只青蛙了。

cpp 复制代码
class Solution 
{
public:
    int minNumberOfFrogs(string croakOfFrogs) 
    {
        string t = "croak";
        int n = t.size();
        //我们不用真的建一个哈希表 只需要一个数组就好了
        vector<int> hash(n);//用数组来模拟哈希表----数组,数组里面存的是当前元素存在或者不存在,0代表不存在 
        unordered_map<char,int> index;//croak字符,下标
        for(int i = 0; i < n; i++)//将字符串和下标放到哈希表中
        {
            index[t[i]] = i;//t[i]得到字符 i为字符下标
        }
        for(auto ch : croakOfFrogs)//遍历给的字符串
        {
            if(ch == 'c')//如果等于c,判断最后一个是不是存在
            {
                if(hash[n - 1] != 0) hash[n - 1]--;//用hash[下标]是否等于0来判断这个元素存在不存在
                hash[0]++;//hash数组里面的元素 是 0 或者 1 2 3...这些,下标代表第几个数
            }
            else
            { //要获得元素的下标,就要先创建一个哈希表(index)来存元素和他对应的下标,得到下标之后还要看这个元素的前一个存在不存,就要建立一个数组(hash),数组的元素表示这个元素是否存在
                int i = index[ch];//获得当前元素的下标 看看这个下标的元素的前一个值是不是为0,为0那么输入的字符串就不是有效字符串
                if(hash[i - 1] == 0) return -1;
                hash[i - 1]--; hash[i]++;//前一个不是0,就让前一个的个数-1,当前的个数加一
            }
        }
        for(int i = 0; i < n - 1; i++)//这个就是看后面还有没有不是完整的croak的字符串,如果有,那么这个整个字符串就是无效的,就返回-1
        {
            if(hash[i] != 0)
                return -1;
        }
        return hash[n - 1]; //要返回青蛙的个数,就返回hash数组n-1的值就可以了,因为他的值存的是元素存在的个数k有两个,就代表有两个青蛙
    }
};

5、38.外观数列

cpp 复制代码
class Solution 
{
public:
    string countAndSay(int n) 
    {
        
        string ret = "1";//ret开始为1
        for(int i = 1;i < n; i++)//通过找规律可以发现,数字n需要翻译n-1次 要对上一次得到的结果继续进行翻译
        {
            string tmp;
            int len = ret.size();//ret是保存最终解释出来的字符串的结果的
            for(int left = 0, right = 0; right < len;) //字符串里面会有好几组,一组一次for循环  我们需要去用双指针在ret上移动,从前到后对他进行翻译,这个从前到后的双指针移动(翻译)需要执行n-1次才可以翻译出来最终结果
            {
                while(right < len && ret[left] == ret[right]) right++;//如果left和right指向的元素是相同的,那么就让right继续往后移动(一直往后移动)---不能用if要用while
                tmp += to_string(right - left) + ret[left];//现在right指向的是相同的元素的下一个,那么就right-left得到几个,再加ret[left]就得到了中间翻译的结果
                left = right;//把left指针移动到right位置
            }
            ret = tmp;
        }
        return ret;
    }
};
相关推荐
MicroTech20252 小时前
微算法科技(NASDAQ :MLGO)探索量子Hadamard门技术,增强量子图像处理效率
图像处理·科技·算法
进击的小头2 小时前
移动平均滤波器:从原理到DSP ADC采样实战(C语言实现)
c语言·开发语言·算法
历程里程碑2 小时前
Linux 6 权限管理全解析
linux·运维·服务器·c语言·数据结构·笔记·算法
历程里程碑2 小时前
双指针--双数之和
开发语言·数据结构·c++·算法·排序算法·哈希算法·散列表
好学且牛逼的马2 小时前
【Hot100|13-LeetCode 56. 合并区间】
数据结构·算法·leetcode
123_不打狼2 小时前
词嵌入模型
人工智能·算法
拼好饭和她皆失2 小时前
图论:拓扑排序讲解,以及 Dijkstra算法,Bellman-Ford算法,spfa算法,Floyd算法模板大全
算法·图论·最短路
爱学习的阿磊2 小时前
模板编译期排序算法
开发语言·c++·算法
皮卡蛋炒饭.2 小时前
动态规划-多重背包
数据结构·算法·动态规划