目录
模拟算法--->"比葫芦画瓢"
特点是:思路简单,主要考察将思路转化为代码的能力。
第一步:模拟算法流程(一定要在演草纸上过一遍流程)
第二步:把流程转化为代码
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;
}
};