标题:【leetcode】模拟
@水墨不写bug
正文开始:
(一)提莫攻击
在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。
当提莫攻击艾希,艾希的中毒状态正好持续
duration
秒。正式地讲,提莫在
t
发起攻击意味着艾希在时间区间[t, t + duration - 1]
(含t
和t + duration - 1
)处于中毒状态。如果提莫在中毒影响结束 前 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在duration
秒后结束。给你一个 非递减 的整数数组
timeSeries
,其中timeSeries[i]
表示提在timeSeries[i]
秒时对艾希发起攻击,以及一个表示中毒持续时间的整数duration
。返回艾希处于中毒状态的 总 秒数。
示例 1:
输入:timeSeries = [1,4], duration = 2 输出:4 解释:提莫攻击对艾希的影响如下: - 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。 - 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。 艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。示例 2:
输入:timeSeries = [1,2], duration = 2 输出:3 解释:提莫攻击对艾希的影响如下: - 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。 - 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。 艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。提示:
1 <= timeSeries.length <= 104
0 <= timeSeries[i], duration <= 107
timeSeries
按 非递减 顺序排列
如果能直接看透本题中毒时间的计算规则的隐含条件,那么你会发现只要重视两次攻击时间差即可。
我们根据模拟题目要求的思路,分情况讨论;
算法思路:
模拟+分情况讨论。
计算相邻两个时间点的差值:
i. 如果差值大于等于中毒时间,说明上次中毒可以持续 duration 秒;
ii. 如果差值小于中毒时间,那么上次的中毒只能持续两者的差值。
参考代码:
class Solution {
public:
int findPoisonedDuration(vector<int>& timeSeries, int duration) {
int n = timeSeries.size(),ret = 0;
if(n == 1) return duration;
for(int i = 1;i < n;i++)
{
int tem = timeSeries[i] - timeSeries[i-1];
tem = tem > duration ? duration : tem;
ret += tem;
}
ret +=duration;
return ret;
}
};
(二)z字型变换
将一个给定字符串
s
根据给定的行数numRows
,以从上往下、从左到右进行 Z 字形排列。比如输入字符串为
"PAYPALISHIRING"
行数为3
时,排列如下:P A H N A P L S I I G Y I R之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,如:
"PAHNAPLSIIGYIR"
。请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);示例 1:
输入:s = "PAYPALISHIRING", numRows = 3 输出:"PAHNAPLSIIGYIR"示例 2:输入:s = "PAYPALISHIRING", numRows = 4 输出:"PINALSIGYAHRPI" 解释: P I N A L S I G Y A H R P I示例 3:
输入:s = "A", numRows = 1 输出:"A"提示:
1 <= s.length <= 1000
s
由英文字母(小写和大写)、','
和'.'
组成1 <= numRows <= 1000
先理解题意,如果n == 1,也就是直接填一条直线,而不是 N 型;这样我们就直接返回原字符串即可。
如果 N > 1 ,这时就需要另做考虑了。
思路一:暴力遍历
创建一个字符型二维数组,所有元素初始化为 ‘ 0 ’ ;按照题目要求填充数组;最终创建string ret,按照从左到右从上到下遍历数组,如果字符不为 ‘0’ ,则尾插到ret中,最终返回ret。
string s1(s);
if(numRows == 1) return s1;
int n = s.size();
char board[numRows][n];
for(int i = 0;i < numRows;i++)
for(int j = 0;j < n;j++)
board[i][j] = 0;
for(int i = 0,row = 0,col = 0;i < n;i++)//这个循环用来遍历字符串
{
if(col %(numRows-1) == 0)//向下填入
{
board[row][col] = s[i];
if(row == numRows - 1) row--,col++;
else row++;
}
else//右上填入
{
board[row][col] = s[i];
if(col %(numRows-1) == 0) row++;
else row--,col++;
}
}
string s2;
for(int i = 0;i < numRows;i++)
for(int j = 0;j < n;j++)
if(board[i][j] != 0)
s2.push_back(board[i][j]);
return s2;
找规律,用 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)的倍数左右取值。
以此规律,我们可以写出迭代算法
class Solution {
public:
string convert(string s, int numRows) {
if(numRows == 1 ) return s;
int d = 2*numRows-2,n = s.size();
string ret;
ret.reserve(n);
//先处理第一行
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;
}
};
(三)外观数列
给定一个正整数
n
,输出外观数列的第n
项。「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。
你可以将其视作是由递归公式定义的数字字符串序列:
countAndSay(1) = "1"
countAndSay(n)
是对countAndSay(n-1)
的描述,然后转换成另一个数字字符串。前五项如下:
1. 1 2. 11 3. 21 4. 1211 5. 111221 第一项是数字 1 描述前一项,这个数是1
即 “ 一 个 1 ”,记作"11"
描述前一项,这个数是11
即 “ 二 个 1 ” ,记作"21"
描述前一项,这个数是21
即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是1211
即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"
要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。
例如,数字字符串
"3322251"
的描述如下图:示例 1:
输入:n = 1 输出:"1" 解释:这是一个基本样例。示例 2:
输入:n = 4 输出:"1211" 解释: countAndSay(1) = "1" countAndSay(2) = 读 "1" = 一 个 1 = "11" countAndSay(3) = 读 "11" = 二 个 1 = "21" countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"提示:
1 <= n <= 30
class Solution {
public:
string countAndSay(int n) {
string s("1");
for(int re = 0;re < n-1;re++)//决定进行多少次循环
{
int len = s.size();
string ret("");
for(int left = 0,right = 0;right < len;) //双指针遍历字符串
{
while(right < len && s[right] == s[left]) right++;
char count = (char)(right -left) + '0';
char ch = s[left];
ret += count;ret += ch;
left = right;
}
s = ret;
}
return s;
}
};
(四)数青蛙
给你一个字符串
croakOfFrogs
,它表示不同青蛙发出的蛙鸣声(字符串"croak"
)的组合。由于同一时间可以有多只青蛙呱呱作响,所以croakOfFrogs
中会混合多个“croak”
。请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。
要想发出蛙鸣 "croak",青蛙必须 依序 输出
‘c’, ’r’, ’o’, ’a’, ’k’
这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。如果字符串croakOfFrogs
不是由若干有效的 "croak" 字符混合而成,请返回-1
。示例 1:
输入:croakOfFrogs = "croakcroak" 输出:1 解释:一只青蛙 “呱呱” 两次示例 2:
输入:croakOfFrogs = "crcoakroak" 输出:2 解释:最少需要两只青蛙,“呱呱” 声用黑体标注 第一只青蛙 "crcoakroak" 第二只青蛙 "crcoakroak"示例 3:
输入:croakOfFrogs = "croakcrook" 输出:-1 解释:给出的字符串不是 "croak" 的有效组合。提示:
1 <= croakOfFrogs.length <= 105
- 字符串中的字符只有
'c'
,'r'
,'o'
,'a'
或者'k'
class Solution {
public:
int minNumberOfFrogs(string croakOfFrogs) {
string str("croak");//随机字符串
int len = str.size();
vector<int> hash(len);//模拟一个哈希表
unordered_map<char,int> index;//为了快速找到前驱下标,将随机字符和下标关联起来
for(int i = 0;i < len;i++)
index[str[i]] = i;
for(const auto ch: croakOfFrogs)
{
if(ch == 'c')
{
if(hash[len-1] != 0) hash[len-1]--;
hash[0]++;
}
else
{
int i = index[ch];
if(hash[i-1] == 0) return -1;
hash[i]++;hash[i-1]--;
}
}
for(int i = 0;i < len-1;i++)
if(hash[i] != 0) return -1;
return hash[len-1];
}
};
/*
unordered_map<char,int> hash;
//遍历蛙鸣字符串
int len = croakOfFrogs.size();
for(int i = 0;i < len;i++)
{
if(croakOfFrogs[i] == 'c')
{
if(hash['k'] > 0)
hash['k']--,hash['c']++;
else
hash['c']++;
}
else if(croakOfFrogs[i] == 'r')
{
if(hash['c'] > 0)
hash['c']--,hash['r']++;
else
return -1;
}
else if(croakOfFrogs[i] == 'o')
{
if(hash['r']>0)
hash['r']--,hash['o']++;
else
return -1;
}
else if(croakOfFrogs[i] == 'a')
{
if(hash['o']>0)
hash['o']--,hash['a']++;
else
return -1;
}
else if(croakOfFrogs[i] == 'k')
{
if(hash['a']>0)
hash['a']--,hash['k']++;
else
return -1;
}
}
if(hash['c'] || hash['r'] || hash['o'] || hash['a']) return -1;
return hash['k'];
*/