《算法题讲解指南:优选算法-模拟》--41.外观数列,42.数青蛙

《算法题讲解指南:优选算法-模拟》--41.外观数列,42.数青蛙

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》

《C++入门到进阶&自我学习过程记录》《算法题讲解指南》--从优选到贪心

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

41.外观数列

题目链接:

题目描述:

题目示例:

解法(模拟):

算法思路:

C++算法代码:

算法总结及流程解析:

42.数青蛙

题目链接:

题目描述:

题目示例:

解法(模拟+分情况讨论):

算法思路:

C++算法代码:

算法总结及流程解析:

结束语


41.外观数列

题目链接:

38. 外观数列 - 力扣(LeetCode)

题目描述:

题目示例:

解法(模拟):

算法思路:

      所谓【外观数列】,其中只是依次统计字符串中连续且相同的字符的个数。依据题意,依次模拟即可。

C++算法代码:

class Solution { public: // string func(string s) // { // string ret; // int left = 0, right = 0, len = 0; // while(right < s.size()) // { // if(s[right] == s[left]) // { // right++; // } // else // { // len = right - left; // ret += to_string(len); // ret += s[left]; // left = right; // } // } // len = right - left; // ret += to_string(len); // ret += s[left]; // return ret; // } string countAndSay(int n) { // string ret = "1"; // while(--n) // { // ret = func(ret); // } // return ret; string ret = "1"; while(--n) { string s; //巧妙用一下双指针来获取相同数字的长度 int left = 0, right = 0, len = 0; while(right < ret.size()) { if(ret[right] == ret[left]) { right++; } else { len = right - left; s += to_string(len);//to_string可以将数字转换出字符 s += ret[left]; left = right; } } len = right - left; s += to_string(len); s += ret[left]; ret = s; } return ret; } };

算法总结及流程解析:

42.数青蛙

题目链接:

1419. 数青蛙 - 力扣(LeetCode)

题目描述:

题目示例:

解法(模拟+分情况讨论):

算法思路:

      模拟青蛙的叫声。

  • 当遇到 'r'  'o'  'a'  'k' 这四个字符的时候,我们要去看看每一个字符对应的前驱字符,有没有青蛙叫出来。如果有青蛙叫出来,那么就让这个青蛙接下来喊出这个字符;如果没有,直接返回 -1;
  • 当遇到 ‘c’ 这个字符的时候,我们去看看 ‘k’ 这个字符有没有青蛙叫出来。如果有,就让这个青蛙继续去 ‘c’ 这个字符;如果没有的话,就重新整一个青蛙出来

C++算法代码:

class Solution { public: int minNumberOfFrogs(string croakOfFrogs) { // //暴力算法:模拟 // //通过一个数组hash模拟存放croak这五个字母 // int n = croakOfFrogs.size(); // vector<int> hash(5, 0); // for(int i = 0; i < n; i++) // { // if(croakOfFrogs[i] == 'c') // { // if(hash[4]) // { // hash[4]--; // } // hash[0]++; // } // else if(croakOfFrogs[i] == 'r') // { // if(hash[0]-- == 0) // { // return -1; // } // hash[1]++; // } // else if(croakOfFrogs[i] == 'o') // { // if(hash[1]-- == 0) // { // return -1; // } // hash[2]++; // } // else if(croakOfFrogs[i] == 'a') // { // if(hash[2]-- == 0) // { // return -1; // } // hash[3]++; // } // else // { // if(hash[3]-- == 0) // { // return -1; // } // hash[4]++; // } // } // for(int i = 0; i < hash.size() - 1; i++) // { // if(hash[i] != 0) // { // return -1; // } // } // return hash[4]; //代码优化:使用一个哈希表存放croak在数组hash中对应的下标,便于快速访问 //就可以不用像上面那样用五个if else来分别判断 string s = "croak"; int n = s.size(); vector<int> hash(n, 0);//用数组模拟哈希表hash来存放croak几个字符 unordered_map<char, int> index; //存放字符所对应在数组hash中的下标 for(int i = 0; i < n; i++) { index[s[i]] = i; } for(int i = 0; i < croakOfFrogs.size(); i++) { int x = index[croakOfFrogs[i]]; //获取到当前字符的下标 if(x != 0) //当前字符为r、o、a、k { if(hash[x - 1]-- == 0) { return -1; } hash[x]++; } else//当前字符为c { if(hash[n - 1]) { hash[n - 1]--; } hash[x]++; } } //如果遍历完字符串后数组hash中除了最后一位k有值, //还有其他字符也有值,则说明有传声还没有完成,则返回-1 for(int i = 0; i < n - 1; i++) { if(hash[i] != 0) { return -1; } } return hash[n - 1]; } };

算法总结及流程解析:

结束语

      到此,41.外观数列,42.数青蛙 这两道算法题就讲解完了。外观数列:模拟统计连续相同字符的个数并生成新字符串。通过双指针计数,迭代n-1次得到结果。数青蛙:通过模拟青蛙叫声过程,分析字符序列croak的匹配逻辑。算法使用哈希表记录字符位置,并动态维护各阶段字符计数:当遇到c时复用已完成k的青蛙或新增青蛙;其他字符则需前驱字符存在才能继续。最后检查未完成序列的青蛙数量。希望大家能有所收获!

Read more

【数据结构指南】高频二叉树节点问题

【数据结构指南】高频二叉树节点问题

前言:               在熟练掌握二叉树四种基本遍历方法的基础上,本文将深入探讨以下进阶问题:节点总数统计、叶子节点计算、第k层节点数量确定、节点的查找以及树高测量。         这些内容将帮助读者深化对二叉树结构的理解与应用能力,以及深入理解递归分治思想。            一、前置说明:          本文所描述的二叉树都是链式二叉树,其定义方式如下所示:          typedef char BTDataType; typedef struct BinaryTree { BTDataType data; struct BinaryTree* left; struct BinaryTree* right; }BTNode;          二、二叉树的创建及销毁          通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树,其中'#'表示该节点为NULL,二叉树如下图所示:                   前序遍历的思想为: 先访问根节点  ->  再访问左子树 -&

By Ne0inhk

LeetCode-Hot100 31.K个一组反转链表

【保姆级详解】K 个一组翻转链表(迭代解法) K个一组翻转链表 是链表操作类算法题中的经典进阶题,它不仅融合了「链表反转」的核心逻辑,还需要处理分组、边界拼接等复杂场景。本文会从问题拆解、核心思路、代码逐行解析、执行流程模拟四个维度,把这道题的迭代解法讲透,方便你复习时快速理解每一个细节。 一、问题描述 题目要求 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。 * k 是一个正整数,它的值小于或等于链表的长度。 * 如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。 * 要求:不能只是单纯改变节点内部的值,而是需要实际进行节点交换。 示例 * 输入:head = [1,2,3,4,5], k = 2 * 输出:[2,1,4,

By Ne0inhk
【强化学习】深度确定性策略梯度算法(DDPG)详解(附代码)

【强化学习】深度确定性策略梯度算法(DDPG)详解(附代码)

📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:        【强化学习】- 【单智能体强化学习】(10)---《深度确定性策略梯度算法(DDPG)详解》 深度确定性策略梯度算法(DDPG)详解 目录 DDPG算法详细介绍 算法特点 核心改进点 算法公式推导 1. Q值函数更新 2. 策略更新(Actor网络) 3. 目标网络更新 算法流程 [Python] DDPG算法实现 1. 导入必要库 2. 定义 Actor 网络 3. 定义 Critic 网络 4. 定义经验回放池 5.

By Ne0inhk
【动态规划】数位DP的原理、模板(封装类)

【动态规划】数位DP的原理、模板(封装类)

本文涉及知识点 C++动态规划 复杂但相对容易理解的解法 上界、下界的位数一样都为N。如果不一样,拆分一样。比如:[10,200],拆分[10,99]和[100,200]。由于要枚举到 1 ∼ N 1\sim N 1∼N,故实际复杂度是N倍。 动态规划的状态表示 dp[n][m][m1],n表示已经处理最高n位,m表示上下界状态:0非上下界,1下界,2上界,3上下界。m1是自定义状态。 某题范围是[110,190],处理一位后:1是上下界,无其它合法状态。处理二位后,11是下界,19是上界, 12 ∼ 18 12

By Ne0inhk