硅基计划4.0 算法 模拟
硅基计划4.0 算法 模拟
文章目录
- 硅基计划4.0 算法 模拟
- 一、替换所有的问号
- 二、提莫攻击
- 三、N字型变换
- 四、外观数列
- 五、数青蛙
模拟说白了就是根据题目要求完成代码就好,但是重点在于代码设计和编写上
一、替换所有的问号
题目链接
这一题的意思其实很简单,只需要保证替换的字符和其前后两个位置不一样就好了
因此我们可以尝试放入字母a
到z
,然后检查其前后是否都不同就好
对于边界情况,如果?
处于最前面和最后面,我们仅需要判断前面或后面即可
class Solution {public String modifyString(String s) {char [] ch = s.toCharArray();int length = ch.length;for(int i = 0;i<length;i++){if(ch[i] == '?'){//遍历字母for(char chs = 'a';chs<'z';chs++){//这里判断非常巧妙,考虑到了边界情况//比如如果i==0,那么chs != ch[i-1]代码就不会执行//就会去执行后半部分的chs != ch[i+1]代码if((i == 0 || chs != ch[i-1]) && (i == length-1 || chs != ch[i+1])){ch[i] = chs;break;}}}}return String.valueOf(ch);}
}
二、提莫攻击
题目链接
比如1 2 3 4
总共四秒,如果中毒时间duration = 2
则我在第一秒进行攻击,中毒会在第二秒后(第三秒开始的时候)结束
但是我在第二秒又进行攻击,时间会重置,中毒会在第三秒后(第四秒开始的时候)才结束
题目示例中[1,4]
,duration = 2
,表示会在第一秒和第四秒进行攻击,中毒时间持续两秒
在第一秒受到攻击,中毒会持续到第三秒开始时(第三秒开始时中毒效果结束)
第四秒开始时,又受到攻击,中毒会持续到第六秒开始时(第六秒开始时中毒效果结束)
题目示例中[1,2]
,duration = 2
,表示会在第一秒和第二秒进行攻击,中毒时间持续两秒
在第一秒受到攻击,本应该在第三秒开始时结束,但是第二秒又受到攻击,时间重置
中毒会持续到第四秒开始时结束(第四秒开始时中毒效果结束)
好,我们通过上面示例可以发现,如果两次攻击间隔是>=duration
时间的
会导致第一次的攻击的中毒效果不会影响到第二次攻击的中毒效果,也就是说第一次攻击可以把中毒buff吃满
反而如果两次攻击间隔是<duration
的,会导致第一次攻击的中毒效果持续时间被第二次攻击重置
好,我们来举个例子[1,3,6,7]
,duration = 2
第一秒受到攻击,第三秒再次受到攻击,和第一次时间差值=duration
,因此第一次攻击吃满中毒持续时间
第六秒再次受到攻击,和第二次时间差值>duration
,因此上一次攻击依然吃满中毒持续时间
第七秒再次受到攻击,和第二次时间差值<duration
,因此上一次攻击并不能吃满中度持续时间,中毒时间是7-6=1
此后再没受到攻击,但是不要忘记第七秒受到了攻击,因此最后还要吃满一次中毒持续时间
class Solution {public int findPoisonedDuration(int[] timeSeries, int duration) {//因为最后一次的后面没有再攻击了//因此把最后一次的中毒时间提前加上int ret = duration;for(int i = 1;i<timeSeries.length;i++){int distance = timeSeries[i]-timeSeries[i-1];if(distance >= duration){ret += duration;}else{ret += distance;}}return ret;}
}
三、N字型变换
题目链接
这道题就是说根据一个字符串创建一个N
字型矩阵,再逐行读取就好
比如abcdefg
,要求numRows = 3
a e
b d f
c
好,我们可以这样,准备一个矩阵,根据坐标(x,y)
排列,就拿刚刚那个示例来说
我们先完成第一列,即先固定y
,然后x
一直到numRows-1
位置停止
再斜向上走,一直到x = 0
时再固定y
,向下走,重复过程
class Solution {public String convert(String s, int numRows) {if (numRows == 1) return s;//创建每行的 StringBuilderStringBuilder[] rows = new StringBuilder[numRows];for (int i = 0; i < numRows; i++) {rows[i] = new StringBuilder();}int currentRow = 0;boolean goingDown = false; //初始方向for (char c : s.toCharArray()) {rows[currentRow].append(c);//到达顶部或底部时改变方向if (currentRow == 0 || currentRow == numRows - 1) {goingDown = !goingDown;}//根据方向移动行currentRow += goingDown ? 1 : -1;}//合并所有行StringBuilder result = new StringBuilder();for (StringBuilder row : rows) {result.append(row);}return result.toString();}
}
但是这样不免时间复杂度太高,我们试试找找规律
我们可以试试在举证中填入下标
class Solution {public String convert(String s, int numRows) {if(numRows == 1){return s;}StringBuilder ret = new StringBuilder();int distance = 2*numRows-2;int length = s.length();//处理第一行for(int i = 0;i<length;i+=distance){ret.append(s.charAt(i));}//处理中间行for(int r = 1;r<numRows-1;r++){for(int i = r,j = distance-r;i < length || j < length;i += distance,j += distance){if(i < length){ret = ret.append(s.charAt(i));}if(j < length){ret = ret.append(s.charAt(j));}}}//处理最后一行for(int i = numRows-1;i<length;i +=distance){ret = ret.append(s.charAt(i));}return ret.toString();}
}
四、外观数列
题目链接
这一题就是对每一行的描述,注意:描述每一行时候,描述的是相邻的同类型的元素
1 <–第一行
1 1 <–第二行,描述:上一行有1个1
2 1 <–第三行,描述:上一行有2个1
1 2 1 1 <–第四行,描述:上一行有1个2,1个1
1 1 1 2 2 1 <–第五行,描述:上一行有1个1,1个2,两个1
3 1 2 2 1 1 <–第六行,描述:上一行有3个1,2个2,1个1
…
我们可以接住双指针模拟,同时在起始位,向后寻找与前一个指针不同的位置,然后统计个数
之后前一个指针移动到现在指针的位置,继续向后走…
class Solution {public String countAndSay(int n) {String str = "1";//第一行不用描述了for(int i = 1;i<n;i++){StringBuilder ret = new StringBuilder();int left = 0;int right = 0;int length = str.length();while(right < length){while(right < length && str.charAt(right) == str.charAt(left)){right++;}//计算个数ret.append(right-left);//该个数属于哪个元素类型ret.append(str.charAt(left));left = right;}str = ret.toString();}return str;}
}
五、数青蛙
题目链接
这道题重点在于理解
因此我们要用一个哈希表统计出现次数,具体请看
总结一下
- 碰到
c
字符,找到最后字符k
,然后判断其内部的值- 如果值是0,说明还没有任何一只青蛙叫完,直接当前字符
c
++就好 - 如果不是0,说明已经有青蛙叫完,我们的
k
值要 - -,当前字符c
++
- 如果值是0,说明还没有任何一只青蛙叫完,直接当前字符
- 如果是其他字符,找到其前驱字符的值
- 如果前驱字符的值不为0,那就前驱字符的个数 - -,当前字符个数++
- 否则直接返回-1,不再需要往后遍历
- 如果是合法的字符串,最后在哈希表中只会剩下字符
k
有值,其他值都为0,因为青蛙都叫完了嘛
class Solution {public int minNumberOfFrogs(String croakOfFrogs) {char[] croakOfFrog = croakOfFrogs.toCharArray();String t = "croak";int n = t.length();//数组模拟哈希表,hash[0]对应字符c,值对应出现个数int[] hash = new int[n];//我们每次要找到当前字符的前驱字符,因此需要哈希表去给字符命名其下标//即字符和下标的哈希映射关系//[x, x这个字符对应的下标],找前驱节点时仅需要下标减一就好Map<Character, Integer> index = new HashMap<>(); for(int i = 0; i < n; i++){index.put(t.charAt(i), i);}for(char ch : croakOfFrog){//字符等于c的情况if(ch == t.charAt(0)){//最后一个字符k判断其内部的值if(hash[n - 1] != 0){hash[n - 1]--;}hash[0]++;}else{//寻找前驱字符int i = index.get(ch);if(hash[i - 1] == 0){return -1;}hash[i - 1]--; hash[i]++;}}//判断在哈希表中是否存在除字符k以外的字符值不为0的情况for(int i = 0; i < n - 1; i++){if(hash[i] != 0){return -1;}}//返回字符k的值就好return hash[n - 1];}
}