[LC优选算法#13] 模拟 | 替换所有的问号 | 提莫攻击 | Z字形变换

顾名思义,模拟就是比着葫芦画瓢,即跟着题目的意思写代码,思路较为简单。解决这类题的步骤为:

  1. 模拟算法流程画图分析很重要!一定要过一遍流程再写)
  2. 把流程转化为代码

1. 替换所有的问号

替换所有的问号

解题思路:

  1. 模拟 O(N): 从前往后遍历整个字符串,遇到问号后,尝试用a~z的每一个字符替换即可。

注意点 :需要对首尾字符分类讨论(因为首尾字符的两侧并不是都有字符,不分类会越界访问)。

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 || s[i - 1] != ch) && (i == n - 1 || s[i + 1] != ch))
                    {
                        s[i] = ch;
                        break;
                    }
                }
            }
        }

        return s;
    }
};

2. 提莫攻击

提莫攻击

解题思路模拟 + 分类讨论

计算相邻两个时间点的差值

  1. 如果差值大于等于 duration,则说明实际中毒时间就是durantion
  2. 如果差值小于 duration,则中毒时间为差值。

注意点 :特别留意变量的初始化和最后一次攻击 的情况,因为利用差值计算sum(总时间)时,不会将最后一次攻击的时间计入,因此要将sum初始化为duration

cpp 复制代码
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration)
    {
        int sum = duration; //最后一次
        int n = timeSeries.size();
        for(int i=1; i<n; i++)
        {
            if(timeSeries[i] - timeSeries[i - 1] >= duration)
            {
                sum += duration;
            }
            else
            {
                sum += timeSeries[i] - timeSeries[i - 1];
            }
        }

        return sum;
    }
};

3. Z字形变换

Z字形变换

解题思路:

  1. 模拟填数 :最直接的解法就是模拟填入数据的过程,按顺序一个个放入新的二维数组中,再遍历数组得到新的字符串。时空复杂度均为O(s.size() * N)
  2. 模拟 + 找规律 :对于矩阵填数这类型的题,我们都可以通过找规律来优化时空复杂度。
    首先,用row表示行数,找出填入数据对应下标 的规律:

    可以发现,数据是以2*row-2为一个周期进行规律变换的,以第四行为例,可将所有数的下标用周期表示,如上图。所以,我们可以根据规律,令d2*row-2,直接拼凑出需要返回的字符串:
cpp 复制代码
class Solution {
public:
    string convert(string s, int numRows)
    {
        int d = 2*(numRows - 1);
        int n = s.size();
        string ret;
        if(numRows == 1) return s;

        //第一行
        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;
    }
};

// 本期内容就到这里啦,如果对你有帮助,请三连支持!我是青云,我们下期见^_~