Offer必备算法05_模拟_五道力扣OJ题详解(由易到难)

这篇具有很好参考价值的文章主要介绍了Offer必备算法05_模拟_五道力扣OJ题详解(由易到难)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

模拟算法原理

①力扣1576. 替换所有的问号

解析代码

②力扣495. 提莫攻击

解析代码

③力扣6. Z 字形变换

解析代码

④力扣38. 外观数列

解析代码

⑤力扣1419. 数青蛙

解析代码1

解析代码2

本篇完。


模拟算法原理

        模拟算法是一种常用的计算机算法,它模拟了实际问题的运行过程,并通过数学模型来预测结果。模拟算法可以应用于各个领域,例如物理、化学、生物、计算机网络等等。

        模拟算法,用一句老话说,就是“照着葫芦画瓢”,官方化的诠释则是:根据题目表述进行筛选提取关键要素,按需求书写代码解决实际问题。

        模拟算法一般都是一些很基础的题目,一些大佬眼中,模拟题就是所谓的“水题”,不太需要动脑子,只要按照题目要求来就好。但是模拟题也分难易,对于一些特困难的模拟题,哪怕是大佬,也很容易做错。大部分模拟题的优化思路都是找规律。


①力扣1576. 替换所有的问号

1576. 替换所有的问号

难度 简单

给你一个仅包含小写英文字母和 '?' 字符的字符串 s,请你将所有的 '?' 转换为若干小写字母,使最终的字符串不包含任何 连续重复 的字符。

注意:你 不能 修改非 '?' 字符。

题目测试用例保证  '?' 字符 之外,不存在连续重复的字符。

在完成所有转换(可能无需转换)后返回最终的字符串。如果有多个解决方案,请返回其中任何一个。可以证明,在给定的约束条件下,答案总是存在的。

示例 1:

输入:s = "?zs"
输出:"azs"
解释:该示例共有 25 种解决方案,从 "azs" 到 "yzs" 都是符合题目要求的。只有 "z" 是无效的修改,因为字符串 "zzs" 中有连续重复的两个 'z' 。

示例 2:

输入:s = "ubv?w"
输出:"ubvaw"
解释:该示例共有 24 种解决方案,只有替换成 "v" 和 "w" 不符合题目要求。因为 "ubvvw" 和 "ubvww" 都包含连续重复的字符。

提示:

  • 1 <= s.length <= 100

  • s 仅包含小写英文字母和 '?' 字符

class Solution {
public:
    string modifyString(string s) {

    }
};

解析代码

思路就是遍历字符串找问号,找到后依次比较前一个字母和后一个字母,都不一样就替换问号。

class Solution {
public:
    string modifyString(string s) {
        int n = s.size();
        for(int i = 0; i < n; ++i)
        {
            if(s[i] == '?')
            {
                for(char c = 'a'; c < 'z'; ++c)
                {
                    if((i == 0 || s[i-1] != c) && (i == n-1 || s[i+1] != c))
                    {   // 或就是i==0就不用判断后面条件了
                        s[i] = c;
                    }
                }
            }
        }
        return s;
    }
};

②力扣495. 提莫攻击

495. 提莫攻击

难度 简单

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。

当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。

正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束  再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。

给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。

返回艾希处于中毒状态的  秒数。

示例 1:

输入:timeSeries = [1,4], duration = 2
输出:4
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 4 秒,提莫再次攻击艾希,艾希中毒状态又持续 2 秒,即第 4 秒和第 5 秒。
艾希在第 1、2、4、5 秒处于中毒状态,所以总中毒秒数是 4 。

示例 2:

输入:timeSeries = [1,2], duration = 2
输出:3
解释:提莫攻击对艾希的影响如下:
- 第 1 秒,提莫攻击艾希并使其立即中毒。中毒状态会维持 2 秒,即第 1 秒和第 2 秒。
- 第 2 秒,提莫再次攻击艾希,并重置中毒计时器,艾希中毒状态需要持续 2 秒,即第 2 秒和第 3 秒。
艾希在第 1、2、3 秒处于中毒状态,所以总中毒秒数是 3 。

提示:

  • 1 <= timeSeries.length <= 10^4
  • 0 <= timeSeries[i], duration <= 10^7
  • timeSeries 按 非递减 顺序排列
class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {

    }
};

解析代码

(十年老玩家最先想到提莫没学E怎么让别人中毒/不是)

        当上次中毒已经结束了,那么上次「中毒」维持的时间就是 duration,如果上次中毒还没有结束,由于中毒状态将会重置,所以上次「中毒」维持的时间 = 当前中毒时间 - 上次中毒时间。

一个for循环就秒了:

class Solution {
public:
    int findPoisonedDuration(vector<int>& timeSeries, int duration) {
        int ret = 0;
        for (int i = 1; i < timeSeries.size(); ++i) 
        {
            ret += min(duration, timeSeries[i] - timeSeries[i - 1]);
        }
        return ret + duration; // 最后一次中毒持续时间加上
    }
};

③力扣6. Z 字形变换

6. Z 字形变换

难度 中等

将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

比如输入字符串为 "PAYPALISHIRING" 行数为 3 时,排列如下:

P   A   H   N
A P L S I I G
Y   I   R

之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"

请你实现这个将字符串进行指定行数变换的函数:

string convert(string s, int numRows);

示例 1:

输入:s = "PAYPALISHIRING", numRows = 3
输出:"PAHNAPLSIIGYIR"

示例 2:

输入:s = "PAYPALISHIRING", numRows = 4
输出:"PINALSIGYAHRPI"
解释:
P     I    N
A   L S  I G
Y A   H R
P     I

示例 3:

输入:s = "A", numRows = 1
输出:"A"

提示:

  • 1 <= s.length <= 1000
  • s 由英文字母(小写和大写)、',' 和 '.' 组成
  • 1 <= numRows <= 1000
class Solution {
public:
    string convert(string s, int numRows) {

    }
};

解析代码

暴力解法就是开一个n*len的二维数组,填输出然后遍历,这样时间空间复杂度都是O(N^2),

绝大部分模拟题的优化方法都是找规律,先画出下面第一个图:(数字代表数组下标)

Offer必备算法05_模拟_五道力扣OJ题详解(由易到难),⑧Offer必备算法(由易到难刷题),⑤高阶数据结构与算法(C++描述),leetcode,算法,哈希算法,模拟题,数据结构,蓝桥杯,学习方法

        通过第一个图发现每隔竖着的一列都能用一个公差d来计算,公差d = 2 * numRows - 2,比如第一个图的公差d = 2 * 4 - 2 = 6,然后就发现完整竖列中间的下标和左边竖列下标加起来刚好等于d,第k行一次遍历两个下标,最后一行和第一行类似,,此时就能通过直接遍历数组的下标得到要返回的字符串:

首先遍历第一行(设下标为i,要返回的字符串为ret,原字符串为s):ret += s[i + d];

        然后遍历中间行(设中间行为k,k>=1,k<=numRows -1,要避免数组越界):

ret += s[k+i + d]; ret += s[d-k + d];(k++,i += d,j = k-d,j+= d)

最后遍历最后一行:ret += s[numRows-1 + i];

class Solution {
public:
    string convert(string s, int numRows) {
        if(numRows == 1) // 处理边界
            return s;

        string ret;
        int n = s.size(), d = 2 * numRows - 2;
        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)
            {                    // i < n 和 j < n都要加到ret里
                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;
    }
};

④力扣38. 外观数列

38. 外观数列

难度 中等

给定一个正整数 n ,输出外观数列的第 n 项。

「外观数列」是一个整数序列,从数字 1 开始,序列中的每一项都是对前一项的描述。

你可以将其视作是由递归公式定义的数字字符串序列:

  • countAndSay(1) = "1"
  • countAndSay(n) 是对 countAndSay(n-1) 的描述,然后转换成另一个数字字符串。

前五项如下:

1.     1
2.     11
3.     21
4.     1211
5.     111221
第一项是数字 1 
描述前一项,这个数是 1 即 “ 一 个 1 ”,记作 "11"
描述前一项,这个数是 11 即 “ 二 个 1 ” ,记作 "21"
描述前一项,这个数是 21 即 “ 一 个 2 + 一 个 1 ” ,记作 "1211"
描述前一项,这个数是 1211 即 “ 一 个 1 + 一 个 2 + 二 个 1 ” ,记作 "111221"

要 描述 一个数字字符串,首先要将字符串分割为 最小 数量的组,每个组都由连续的最多 相同字符 组成。然后对于每个组,先描述字符的数量,然后描述字符,形成一个描述组。要将描述转换为数字字符串,先将每组中的字符数量用数字替换,再将所有描述组连接起来。

例如,数字字符串 "3322251" 的描述如下图:

Offer必备算法05_模拟_五道力扣OJ题详解(由易到难),⑧Offer必备算法(由易到难刷题),⑤高阶数据结构与算法(C++描述),leetcode,算法,哈希算法,模拟题,数据结构,蓝桥杯,学习方法

示例 1:

输入:n = 1
输出:"1"
解释:这是一个基本样例。

示例 2:

输入:n = 4
输出:"1211"
解释:
countAndSay(1) = "1"
countAndSay(2) = 读 "1" = 一 个 1 = "11"
countAndSay(3) = 读 "11" = 二 个 1 = "21"
countAndSay(4) = 读 "21" = 一 个 2 + 一 个 1 = "12" + "11" = "1211"

提示:

  • 1 <= n <= 30
class Solution {
public:
    string countAndSay(int n) {

    }
};

解析代码

就是一道需要用到双指针的模拟题,考验代码能力

class Solution {
public:
    string countAndSay(int n) {
        string ret = "1", tmp = "";
        int cnt = n;
        while(--cnt) // 解释n-1次
        {
            int len = ret.size();
            tmp = "";
            for(int left = 0, right = 0; right < len; left = right)
            {
                while(right < len && ret[left] == ret[right])
                {   // 双指针计算个数
                    ++right;
                }
                tmp += to_string(right - left);
                tmp += ret[left];
            }
            ret = tmp;
        }
        return ret;
    }
};

⑤力扣1419. 数青蛙

1419. 数青蛙

难度 中等

给你一个字符串 croakOfFrogs,它表示不同青蛙发出的蛙鸣声(字符串 "croak" )的组合。由于同一时间可以有多只青蛙呱呱作响,所以 croakOfFrogs 中会混合多个 “croak” 

请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目。

要想发出蛙鸣 "croak",青蛙必须 依序 输出 ‘c’, ’r’, ’o’, ’a’, ’k’ 这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。如果字符串 croakOfFrogs 不是由若干有效的 "croak" 字符混合而成,请返回 -1 。

示例 1:

输入:croakOfFrogs = "croakcroak"
输出:1 
解释:一只青蛙 “呱呱” 两次

示例 2:

输入:croakOfFrogs = "crcoakroak"
输出:2 
解释:最少需要两只青蛙,“呱呱” 声用黑体标注
第一只青蛙 "crcoakroak"
第二只青蛙 "crcoakroak"

示例 3:

输入:croakOfFrogs = "croakcrook"
输出:-1
解释:给出的字符串不是 "croak" 的有效组合。

提示:

  • 1 <= croakOfFrogs.length <= 10^5
  • 字符串中的字符只有 'c''r''o''a' 或者 'k'

解析代码1

五个if:

class Solution {
public:
    int minNumberOfFrogs(string croakOfFrogs) {
        // int c = 0, r = 0, o = 0, a = 0, k = 0;
        vector<int> arr(6, 0); // 用下标1到5分别映射五个字母
        for(auto& e : croakOfFrogs)
        {
            if(e == 'c')
            {
                if(arr[5] > 0)
                    --arr[5];
                ++arr[1];
            }
            if(e == 'r')
            {
                if(arr[1] > 0)
                    --arr[1];
                else
                    return -1;
                ++arr[2];
            }
            if(e == 'o')
            {
                if(arr[2] > 0)
                    --arr[2];
                else return -1;
                ++arr[3];
            }
            if(e == 'a')
            {
                if(arr[3] > 0)
                    --arr[3];
                else  return -1;
                ++arr[4];
            }
            if(e == 'k')
            {
                if(arr[4] > 0)
                    --arr[4];
                else return -1;
                ++arr[5];
            }
        }
        if(arr[1] > 0 || arr[5] == 0)
            return -1;
        return arr[5];
    }
};

解析代码2

用哈希表:

class Solution {
public:
    int minNumberOfFrogs(string croakOfFrogs) {
        string str = "croak";
        int n = str.size();
        vector<int> arr(n, 0); // 数组模拟哈希表
        unordered_map<char, int> index; //映射每个字符的下标
        for(int i = 0; i < n; ++i)
            index[str[i]] = i;

        for(auto& e : croakOfFrogs)
        {
            if(e == 'c')
            {
                if(arr[n-1] != 0)
                    --arr[n-1];
                ++arr[0];
            }
            else
            {
                if(arr[index[e] - 1] == 0)
                    return -1;
                --arr[index[e] - 1];
                ++arr[index[e]];
            }
        }
        for(int i = 0; i < n-1; ++i)
        {
            if(arr[i] != 0)
                return -1;
        }
        return arr[n-1];
    }
};

本篇完。

下一部分是关于位运算的OJ。文章来源地址https://www.toymoban.com/news/detail-836860.html

到了这里,关于Offer必备算法05_模拟_五道力扣OJ题详解(由易到难)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++ • STL • 力扣】详解string相关OJ

    ヾ(๑╹◡╹)ノ\\\" 人总要为过去的懒惰而付出代价 ヾ(๑╹◡╹)ノ\\\" 力扣链接 代码1展示 :【下标】 代码2展示 :【迭代器】 思路 :快速排序中的单趟排序 知识点 :C++库提供了swap的函数,可以直接调用。 力扣链接 代码展示 : 思路 :计数排序的思想 牛客链接 代码展示 :

    2024年02月09日
    浏览(42)
  • 每日OJ题_算法_滑动窗口⑧_力扣76. 最小覆盖子串

    目录 力扣76. 最小覆盖子串 解析及代码 76. 最小覆盖子串 - 力扣(LeetCode) 难度 困难 给你一个字符串  s  、一个字符串  t  。返回  s  中涵盖  t  所有字符的最小子串。如果  s  中不存在涵盖  t  所有字符的子串,则返回空字符串  \\\"\\\"  。 注意: 对于  t  中重复字符,

    2024年01月23日
    浏览(40)
  • 《剑指offer》(5)搜索算法、位运算、模拟

    方法一: class Solution:     def GetNumberOfK(self , nums: List[int], k: int) - int:         #从两边开始找,找到之后记录当前位置         left = 0         right = len(nums) - 1         if k not in nums:             return 0         start = len(nums) - 1         end = 0         while left = right:      

    2024年02月14日
    浏览(80)
  • 每日OJ题_算法_递归④力扣24. 两两交换链表中的节点

    目录 ④力扣24. 两两交换链表中的节点 解析代码 24. 两两交换链表中的节点 难度 中等 给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。 示例 1: 示例 2: 示例 3: 提示: 链表

    2024年02月20日
    浏览(42)
  • 每日OJ题_算法_滑动窗口⑦_力扣30. 串联所有单词的子串

    目录 力扣30. 串联所有单词的子串 解析及代码 30. 串联所有单词的子串 - 力扣(LeetCode) 难度 困难 给定一个字符串  s   和一个字符串数组  words 。   words  中所有字符串  长度相同 。   s   中的  串联子串  是指一个包含   words  中所有字符串以任意顺序排列连接起来的

    2024年01月21日
    浏览(43)
  • 【力扣算法05】之 _1911_ 最大子序列交替和- python

    一个下标从 0 开始的数组的 交替和 定义为 偶数 下标处元素之 和 减去 奇数 下标处元素之 和 。 比方说,数组 [4,2,5,3] 的交替和为 (4 + 5) - (2 + 3) = 4 。 给你一个数组 nums ,请你返回 nums 中任意子序列的 最大交替和 (子序列的下标 重新 从 0 开始编号)。 一个数组的 子序列

    2024年02月15日
    浏览(36)
  • 每日OJ题_算法_滑动窗口⑥_力扣438. 找到字符串中所有字母异位词

    目录 力扣438. 找到字符串中所有字母异位词 解析及代码1 解析及代码2 438. 找到字符串中所有字母异位词 - 力扣(LeetCode) 难度 中等 给定两个字符串  s  和  p ,找到  s   中所有  p   的  异位词  的子串,返回这些子串的起始索引。不考虑答案输出的顺序。 异位词  指由

    2024年01月24日
    浏览(47)
  • 剑指offer(C++)-JZ29:顺时针打印矩阵(算法-模拟)

    作者:翟天保Steven 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 题目描述: 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 则依次打印出数字 数据范围: 0 = matrix.length = 100 0 = ma

    2024年02月10日
    浏览(41)
  • 【算法第六天7.19】反转字符串,反转字符串||,剑指 Offer 05. 替换空格,反转字符串的单词, 左旋转字符串

    ================================================ 思路 :以中间为分界线,左右两个边界交换字符,依次向里收缩 思路 : 首先:字符串转化为字符数组 char[] res = s.toCharArray(); 最后:将数组再转回字符串 return new String(res); 1、循环以2k为单位, 2、在这个2k长的数组中进行反转,需要有首

    2024年02月16日
    浏览(62)
  • 力扣精选算法100道——提莫攻击(模拟专题)

    目录 🚩题目解析 🚩算法原理 🚩实现代码   我们可以看到 1 是 如果俩次攻击的时间之差是1(前提是俩者相减小于duration) 我们看到俩次攻击时间之差是duration(前提是俩者相减大于等于duration)。3和7的差距是大于duration,所以可以中毒dauration秒。 结论: 中毒时间记为ret,相邻

    2024年02月21日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包