算法日记:模拟(提莫攻击,替换所有的问号,Z字形变换,外观数列,数青蛙)

🎬 胖咕噜的稞达鸭个人主页
🔥 个人专栏 : 《数据结构《C++初阶高阶》
《Linux系统学习》
《算法日记》

⛺️技术的杠杆,撬动整个世界!


模拟:这个专题最重要的就是理解题意。借助纸和笔实现题目中的过程。找出规律即可。

替换所有的问号

[1576. 替换所有的问号 - 力扣(LeetCode)](https://leetcode.cn/problems/replace-all-s-to-avoid-consecutive-repeating-characters/submissions/686036885/)\](替换所有的问号) 题目解析: 字符串中有问号?就替换成26个字母其一,最后返回的字符串中不允许出现重复的字符。 算法原理: 先遍历一遍字符串找出问号,接着替换,用26个英文字母一个一个替换,看是否满足这个空,不能跟左边的字母相同,也不能跟右边的字母相同。 如果s\[i\]问号空有可能在: 要么在字符串的第一个位置,要么是跟前面一个位置的字符不相同; 或者是最后一个位置,要么就是跟后一个位置的字符不相同; (这两个条件要同时满足) 同时满足就插入。 ```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; } }; ``` ### 提莫攻击 题目解析:给定一个时间区间 `[t, t + duration - 1]`(含 `t` 和 `t + duration - 1`)处于中毒状态。有一个不变的量duration,作为每一次\>中毒的持续时长,当第一次中毒之后,还没有恢复(没有超过中毒的持续时长)再次中毒,就会从第二次中毒的时刻重新往后记单次中毒时长。 求解中毒状态的总秒数。 算法原理: ```cpp //下面给定一个时间区间[1,19] duration = 3 1 4 5 8 9 15 19 //第1秒中毒: 中毒区间【1,3】 //第4秒中毒: 中毒区间[4, 6] ---> 由于第5秒又中毒:中毒区间[5,7] //第8秒中毒: 中毒区间[8,10] ---> 由于第9秒又中毒:中毒区间[9,11] //第15秒中毒:中毒区间[15,17] //第19秒中毒:中毒区间[19,21] ``` 先定义一个ret来收集最后的中毒秒数。 遍历数组: 从索引为1的位置开始,如果第一次和第二次中毒的间隔时长大于等于duration,直接计入ret中; 如果第一次和第二次中毒的间隔时长小于duration, 那么该计入第一次中毒时长的只能是两次间隔差。 ```cpp class Solution { public: int findPoisonedDuration(vector& 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; } }; ``` ### Z字形变换 **解法一** :模拟实现(自己画图),将数组中的数字放入一个矩阵中实现;放入之后一行一行遍历,一定会超过时间限制的。 **解法二** :找规律 让一个字符的索引值计入矩阵,这样就可以很清楚找出规律: 行数记为n; 公差d记为2n -2。(第一行中前两个数字的差值为 2n - 2);两列的数字加起来减去两个空格。 所以 第一行规律:0 -> 0+d -> 0+2d ->... 0+kd; 第二行规律: (i, d-i) -> (i+d, d-i+d) 最后一行规律: n-1 -> n-1+d -> n-1+2d ->... n-1+kd; 特殊情况:当只需要1行,直接返回当前数组。 ```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 1. 每个青蛙发出"croak"声音时,可以看作是状态转移 1. 遇到'c': 可能是新青蛙开始叫,也可能是青蛙完成一轮后重新开始 > 1. 遇到其他字符: 必须检查前一个字符是否存在(确保顺序正确) 2. 最终:除了'k',其他字符计数应为0,'k'的计数就是最小青蛙数 ```cpp class Solution { public: int minNumberOfFrogs(string croakOfFrogs) { string t = "croak"; int n = t.size(); vectorhash(n);//用数组来模拟哈希表 unordered_mapindex;//[x,x字符对应的下标] for(int i = 0; i < n;i++)index[t[i]] = i; for(auto ch : croakOfFrogs) { if(ch == 'c') { //如果k在哈希表中存在 if(hash[n - 1] != 0)hash[n-1]--;//此时这种情况就是让同一个青蛙,叫完k之后又从当前c开始叫 hash[0]++;//当k不在哈希表中,另一个青蛙,不管是不是同一个青蛙,字符c都要向后遍历 } else //遍历到'r''o''a''k'字符,看前驱字符在否,不在就说明不能发出声音;在就继续遍历 { int i = index[ch]; if(hash[i-1] == 0)return -1;//前驱字符不存在 else hash[i-1]--;//前驱存在,此时让前驱--,此时的字符++,这样统计到最后的k,就可以判断出需要几个青蛙来叫这一个字符串了 hash[i]++; } } for(int i = 0;i < n - 1;i++) if(hash[i] != 0)return -1;//如果字符串中某一个字符没有被后驱字符修改为hash[i] == 0 说明残缺不全,青蛙叫声不全 return hash[n-1]; } }; ```

相关推荐
努力学算法的蒟蒻4 分钟前
day53(1.4)——leetcode面试经典150
算法·leetcode·面试
leiming67 分钟前
c++ transform算法
开发语言·c++·算法
橘颂TA19 分钟前
【剑斩OFFER】哈希表简介
数据结构·算法·散列表
小尧嵌入式20 分钟前
c++红黑树及B树B+树
开发语言·数据结构·c++·windows·b树·算法·排序算法
tobias.b25 分钟前
408真题解析-2009-10-数据结构-排序
数据结构·算法·排序算法·408考研·408真题·真题解析
Zachary_zlc29 分钟前
有向无环图检测算法和关键路径算法
算法
你撅嘴真丑31 分钟前
素数回文数的个数 与 求分数序列和
算法
Wuliwuliii38 分钟前
贡献延迟计算DP
数据结构·c++·算法·动态规划·dp
ysn1111142 分钟前
简单多边形三角剖分---耳切法(含源码)
算法
e疗AI产品之路43 分钟前
一文介绍Philips DXL心电图算法
算法·pan-tompkins·心电分析