LeetCode--38.外观数列
前言:之前我不是说,我后续可能会讲一下递归吗,现在它来了,这道题会用到回溯的方法,并且比较纯粹哦
解题思路:
1.获取信息:(下面这些信息差不多是力扣上面的题目信息了,所以我这一环节在这次题解中的意义不大)
外观数列是一个数位字符串序列,由递归公式定义:
countAndSay(1) = "1"
countAndSay(n)
是countAndSay(n-1)
的行程长度编码。
行程长度编码(RLE)是一种字符串压缩方法,其工作原理是通过将连续相同字符(重复两次或更多次)替换为字符重复次数(运行长度)和字符的串联。例如,要压缩字符串 "3322251"
,我们将 "33"
用 "23"
替换,将 "222"
用 "32"
替换,将 "5"
用 "15"
替换并将 "1"
用 "11"
替换。因此压缩后字符串变为 "23321511"
。
要求给定一个整数n,返回外观数列的第n个元素,即返回递归公式代入n后的值
2.分析题目:
它给出了递归公式,就是提醒你,可以使用递归来解决这道题
并且说明了行程长度编码压缩字符串的原理,更方便你理解了嘛
现在来讲一下递归:(你可以结合我下面代码来进行理解)
我们都知道,那些使用递归的题中,一般一个函数里面是嵌套着一个相同的函数对吧
例如 Find()函数里面套一个Find()函数
这就是递归的关键之一,你可以理解成,里面套着的那个函数是开启外面这个函数的“钥匙”
现在,外面里面有了一个嵌套的函数对吧,那么在代码执行到那个嵌套的函数时,我们知道,代码是一段一段执行的,对吧,那么在执行完这个嵌套的函数之前,下面的代码它是不会执行的对吧,所以在获取到“钥匙”之前,下面的代码是不会进行操作的
那么,你是不是可以讲它看作是一个深入的过程,它在深入到一定程度后,就会结束,即:获取到“钥匙”,就会开始执行下面的代码,即开始执行外部函数
那么它深入地程度,你可以来进行规定,比如设置一个条件,满足这个条件就返回,就可以返回较浅的层面
这样的话,就有了很多钻空子的操作,我举一个现实的例子来抽象地说一下吧
比如一个车间需要加工一把椅子,老板给你说,让你安排一下,做好了就把自己白富美的女儿嫁给你,让你走上人生巅峰
你现在要做一把椅子,你知道需要椅子的腿,椅子的靠背,椅子的垫子来组成椅子
你没有这些东西,你就算知道怎么把它们组合起来,也不能操作,因为巧妇难为无米之炊(这就是我说的,缺少“钥匙”,你不能进行外部函数下面的代码操作)
这个时候就需要这些东西对吧,那你就需要再加一个更深层次的步骤,将自己的需求传递给这个更深层次的部门
这个更深层次的部门的操作就是将木材加工成上述东西,但是又没有木材,也不能开启它们的操作
需要木材,我们知道,木材就是这次加工的最底线了,对吧,这个底线是人为规定的,意思就是我们希望它是底线,那就是底线,这里就是我说的,深入到一定程度时,需要一个条件来阻止它继续深入,你可以理解成,这个工厂才是你考虑得范围,至于木材怎么来的,你不用管,你只用管你该管的范围,即:题目要求的范围
现在我们取得了木材,那么就返回到了较浅的步骤,就是加工木材的步骤,工人获取了木材,即:“钥匙”,那就可以进行后续操作了,它们进行后续操作了之后,就返回他们加工的东西
我现在获得了组合椅子需要的东西,现在我就可以进行我下面的操作了,我完成了之后,就是结果了,可以交给老板验货
迎娶白富美,走上人生巅峰,毕竟,人人都想成为达叔,软饭硬吃
3.示例查验:
你可以结合示例,来品味一下递归,(上面说的,其实比较偏向回溯,但递归的核心思想还是不会变的)
4.尝试编写代码:
(1)回溯法
思路就不过多阐述了,这道题比较纯粹,就直接上代码了
class Solution {
public:string countAndSay(int n) {if(n==1)return "1";string str=countAndSay(n-1),res;int num=1,size=str.size();for(int i=1;i<=size;i++){if(i==size){res+=(num+'0');res+=str[i-1];break;}if(str[i]==str[i-1])num++;else{res+=(num+'0');res+=str[i-1];num=1;}}return res;}
};
(2)打表嘛
思路:给出了n的范围是1到30,那你直接把1到30每个数得到的结果列举出来,输入n后,直接返回对应结果就可以了,这里就不写代码了,太麻烦了