我爱学算法之—— 模拟(上)

一、替换所有的问号

题目解析

替换所有的问号,给定一个字符串s(其中仅包含?和小写字母);我们要将s中所有的?替换成小写字母,并且还要保证最终的字符串中,不包含连续重复的字符(相邻的字符都不相同

算法思路

对于这道题,总体来说还是非常简单的;只需要按照题目要求遍历s,在遍历到?时将其替换成小写字母(与前一个字符和后一个字符都不相同)。

注意:

当第一个字符为?时,是不存在前一个字符的,只需要保证和后一个字母不相同即可;

当最后一个字符为?时,是不存在后一个字符的,只需要保证和前一个字符不相同即可。

代码实现

cpp 复制代码
class Solution {
public:
    string modifyString(string s) {
        int n = s.size();
        for (int i = 0; i < n; i++) {
            if (s[i] == '?') {
                for (char ch = 'a'; ch <= 'z'; ch++) {
                    if ((i == 0 || ch != s[i - 1]) &&
                        (i == n - 1 || ch != s[i + 1])) {
                        s[i] = ch;
                    }
                }
            }
        }
        return s;
    }
};

二、提莫攻击

题目解析

题目:提莫每次攻击会使艾希中毒duration秒,如果提莫攻击艾希时,艾希处于中毒状态,则时间会重置(不会叠加)。

先给定一个非递减的数组timeSeries,表示提莫攻击艾希的时间(提莫会在timeSeries[i]秒时攻击艾希)。

这道题目要求我们计算出,艾希处于中毒状态的总时间(秒)。

算法思路

对于这道题,思路也是非常简单,按照题目要求遍历timeSeries数组,统计艾希处于中毒状态的时间即可。

通过读题,我们会发现,提莫的最后一次攻击一定会导致艾希处于中毒状态duration秒;

而其他每一次攻击,导致艾希进入中毒状态的时间都和前一次攻击有关。

提莫第i+1次攻击攻击艾希时,无非就只有三种情况:

  • 当前艾希处于中毒状态:重置中毒时间,第i次攻击导致艾希处于中毒状态时间 timeSeries[i+1] - timeSeries[i]
  • 艾希刚好中毒状态解除:艾希进入中毒状态,第i次攻击导致艾希处于中毒状态时间 durationtimeSeries[i+] - timeSeries[i]
  • 艾希没有处于中毒状态:艾希进入中毒状态,第i次攻击导致艾希处于中毒状态时间 duration

所以,提莫第i次攻击,导致艾希的中毒时间:time = min(duration,timeSeries[i+1] - timeSeries[i]

所以,只需遍历[0 , n-2]次攻击,算出艾希中毒的时间再加上duration(第n-1次攻击必定导致艾希中毒duration秒)。

代码实现

cpp 复制代码
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ret = 0;
        int n = timeSeries.size();
        for (int i = 0; i < n - 1; i++) {
            int x = timeSeries[i + 1] - timeSeries[i];
            ret += min(duration, x);
        }
        ret += duration;
        return ret;
    }
};

三、Z 字形变换

题目解析

这道题,给定一个字符串s,这里要将字符串s从上往下,从左往右进行N字形排列;然后再从左往右逐行读取,产生一个新的字符串然后返回。

算法思路

对于这道题,思路就很清楚了:模拟整个过程

思路一:

排列N字形:

将字符串s排列成N字形,这里可以使用一个二维数组,将字符串s排列成如上图所示N字形,再遍历整个数组,形成结果字符串。


但是,这样做时间复杂度和空间复杂度都是O(n * numRows);并且遍历的过程中填写这个二维数组也是非常的麻烦。

这里,我们就可以使用C++中的string进行小小的空间和时间的优化。

优化一 :在填写二维数组的过程中,只需要关注要将字符放在哪一行中(哪一个字符串中)。

优化二 :在形成最终结果字符串时,只需要将字符串按行拼接在一起即可(字符串中不存在空格)。

思路二:

思路二也就是对模拟思路的一个优化:

在模拟过程中,直接将字符放到指定位置可能看不出来,这里使用下标代替字符:


可以发现,第一行的字符下标呈现出一个等差数列,公差为6(也就是这两列中,下面所有行的字符总数)

而最后一行的字符下标,也呈现出一个等差数列,公差为6

而中间的每一行,大眼一看,不是等差数列啊;仔细观察我们可以发现:中间的每一行,可以看成两个等差数列;其中一个数列首项为x,另一个数列首项就为6-x(也就是d - x

公差:显而易见,公差d = 2n - 2


所以,我们只需要先遍历第一行、再遍历中间的每一行、最后遍历最后一行(将每一行下标对应的字符,拼接成一个字符串返回即可)。

遍历的过程中,注意不要越界。

特殊情况:如果numRows等于1,此时计算出公差为0,并且numRows等于1时,无需转换,s就是最终结果。

这里就特殊处理,如果numRows等于1,就直接返回s

代码实现

思路一:

cpp 复制代码
class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1)
            return s;
        int i = 0;
        int flag = 0; // flag 0 -> i++  1 -> i--
        vector<string> vs(numRows, string());
        for (auto& e : s) {
            if (i == 0)
                flag = 0;
            else if (i == numRows - 1)
                flag = 1;
            vs[i] += e;
            if (flag == 0)
                i++;
            else
                i--;
        }
        string ret;
        for (auto& e : vs) {
            ret += e;
        }
        return ret;
    }
};

思路二:

cpp 复制代码
class Solution {
public:
    string convert(string s, int numRows) {
        if (numRows == 1)
            return s;
        int d = 2 * numRows - 2;
        int n = s.size();
        string ret;
        // 第一行
        for (int i = 0; i < n; i += d)
            ret.push_back(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.push_back(s[i]);
                if (j < n)
                    ret.push_back(s[j]);
            }
        }
        // 最后一行
        for (int i = numRows - 1; i < n; i += d)
            ret.push_back(s[i]);
        return ret;
    }
};

本篇文章到这里就结束了,感谢支持

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2oul0hvapjsws

相关推荐
给大佬递杯卡布奇诺3 分钟前
FFmpeg 基本API avcodec_open2函数内部调用流程分析
c++·ffmpeg·音视频
进击的圆儿27 分钟前
高并发内存池项目开发记录 - 02
开发语言·c++·实战·项目·内存池
YXXY31329 分钟前
二叉树进阶
c++
Antonio91536 分钟前
【图像处理】常见图像插值算法与应用
图像处理·算法·计算机视觉
夜晚中的人海38 分钟前
【C++】使用双指针算法习题
开发语言·c++·算法
怀旧,40 分钟前
【Linux系统编程】3. Linux基本指令(下)
linux·开发语言·c++
艾莉丝努力练剑41 分钟前
【C++STL :stack && queue (三) 】优先级队列的使用以及底层实现
linux·开发语言·数据结构·c++·stl
im_AMBER3 小时前
数据结构 06 线性结构
数据结构·学习·算法
earthzhang20215 小时前
【1028】字符菱形
c语言·开发语言·数据结构·c++·算法·青少年编程
papership5 小时前
【入门级-算法-3、基础算法:二分法】
数据结构·算法