算法专题(五):模拟
目录
一、替换所有的问号
1.1 题目
1.2 思路
1.3 代码
二、提莫攻击
2.1 题目
2.2 思路
2.3 代码
三、Z 字形变换
3.1 题目
3.2 思路
3.3 代码
四、外观数列
4.1 题目
4.2 思路
4.3 代码
五、数青蛙
5.1 题目
5.2 思路
5.3 代码
每道题目的标题均是该题的传送门!
模拟算法通俗的讲就是比葫芦画瓢,思路比较简单,考验的是代码能力!
一、替换所有的问号
1.1 题目
1.2 思路
纯模拟。从前往后遍历整个字符串,找到问号之后,就用 a ~ z 的每一个字符去尝试替换即可。
1.3 代码
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;
}
};
二、提莫攻击
2.1 题目
2.2 思路
模拟 + 分情况讨论。
计算相邻两个时间点的差值:
i. 如果差值大于等于中毒时间,说明上次中毒可以持续 duration 秒;
ii. 如果差值小于中毒时间,那么上次的中毒只能持续两者的差值。
2.3 代码
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration)
{
int n = timeSeries.size();
int ret = 0;
for(int i = 1; i < n; i++)
{
if(timeSeries[i] - timeSeries[i-1] < duration)
ret += timeSeries[i] - timeSeries[i-1];
else
ret += duration;
}
ret += duration;
return ret;
}
};
三、Z 字形变换
3.1 题目
3.2 思路
找规律,用 row 代替行数,row = 4 时画出的 N 字形如下:
0 2row - 2 4row - 4
1 2row - 3 2row - 1 4row - 5 4row - 3
2 2row-4 2row 4row - 6 4row - 2
3 2row + 1 4row - 1
不难发现,数据是以 2row - 2 为一个周期进行规律变换的。将所有数替换成用周期来表示的量:
第一行的数是:0, 2row - 2, 4row - 4;
第二行的数是:1, (2row - 2) - 1, (2row - 2) + 1, (4row - 4) - 1, (4row - 4) + 1;
第三行的数是:2, (2row - 2) - 2, (2row - 2) + 2, (4row - 4) - 2, (4row - 4) + 2;
第四行的数是:3, (2row - 2) + 3, (4row - 4) + 3。
可以观察到,第一行、第四行为差为 2row - 2 的等差数列;第二行、第三行除了第一个数取值为行数,每组下标为(2n - 1, 2n)的数围绕(2row - 2)的倍数左右取值。
以此规律,我们可以写出迭代算法。
3.3 代码
注意一下n==1的时候
class Solution {
public:
string convert(string s, int numRows)
{
if(numRows == 1)
return s;
string ret;
int d = 2 * numRows - 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.1 题目
4.2 思路
所谓外观数列,其实只是依次统计字符串中连续且相同的字符的个数。依照题意,依次模拟即
可。
4.3 代码
class Solution {
public:
string countAndSay(int n)
{
string ret = "1";
for(int i = 1; i < n; i++)
{
string tmp;
int left = 0,right = 0;
while(right < ret.size())
{
while(right < ret.size() && ret[left]==ret[right])
right++;
tmp += to_string(right-left) + ret[left];
left = right;
}
ret = tmp;
}
return ret;
}
};
五、数青蛙
5.1 题目
5.2 思路
模拟青蛙的叫声。
◦ 当遇到 'r' 'o' 'a' 'k' 这四个字符的时候,我们要去看看每一个字符对应的前驱字符,有没有青蛙叫出来。如果有青蛙叫出来,那就让这个青蛙接下来喊出来这个字符;如果没有,直接返回 -1;
◦ 当遇到 'c' 这个字符的时候,我们去看看 'k' 这个字符有没有青蛙叫出来。如果有,就让这个青蛙继续去喊 'c' 这个字符;如果没有的话,就重新搞一个青蛙。
5.3 代码
class Solution {
public:
int minNumberOfFrogs(string croakOfFrogs)
{
string t = "croak";
int n = t.size();
vector<int> hash(n);
unordered_map<char,int> arr; [x, x这个字符对应的下标]
for(int i = 0; i < n; i++)
arr[t[i]] = i;
for(auto ch : croakOfFrogs)
{
if(ch == 'c')
{
if(hash[n-1] != 0)
hash[n-1]--;
hash[0]++;
}
else
{
int i = arr[ch];
if(hash[i-1] == 0)
return -1;
hash[i]++;
hash[i-1]--;
}
}
for(int i = 0; i < n-1;i++)
{
if(hash[i] != 0 )
return -1;
}
return hash[n-1];
}
};
本篇完,下篇见!