硅基计划4.0 算法 模拟

硅基计划4.0 算法 模拟


1752388689224



模拟说白了就是根据题目要求完成代码就好,但是重点在于代码设计和编写上

一、替换所有的问号

题目链接
这一题的意思其实很简单,只需要保证替换的字符和其前后两个位置不一样就好了
因此我们可以尝试放入字母az,然后检查其前后是否都不同就好

对于边界情况,如果?处于最前面和最后面,我们仅需要判断前面或后面即可

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;
        
        //创建每行的 StringBuilder
        StringBuilder[] 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();
    }
}

但是这样不免时间复杂度太高,我们试试找找规律
我们可以试试在举证中填入下标
image-20250824100934062

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;
    }
}

五、数青蛙

题目链接
这道题重点在于理解
image-20250824150743271
因此我们要用一个哈希表统计出现次数,具体请看
image-20250824153132355

总结一下

  • 碰到c字符,找到最后字符k,然后判断其内部的值
    • 如果值是0,说明还没有任何一只青蛙叫完,直接当前字符c++就好
    • 如果不是0,说明已经有青蛙叫完,我们的k值要 - -,当前字符c++
  • 如果是其他字符,找到其前驱字符的值
    • 如果前驱字符的值不为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];
    }
}

希望本篇文章对您有帮助,有错误您可以指出,我们友好交流

END
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值