菜鸟寒假刷C,于力扣十题处,苦思,思之三日,终得解,现记之。
题目:
一、常规思路:
本题难点就难在“ * ”重复的次数是未知的,关键就是如何去处理这个“ * ”。在这里,我们选用动态规划的方法便于理解。
“ * ”的情况大致可分为三种:重复0次,重复1次,以及重复2次及以上。重复0次则n[i][j]=n[i][j-2](n是二维数组,其中i对应着字符串s,j对应字符串p), 重复一次则n[i][j]=n[i-1][j-2];当重复两次及以上时,则令n[i][j]=n[i-1][j];相当于舍弃s的一个字符后,再将剩下的与p进行判断。
解决了最难的点后,接下来我们讨论如何去定义n,和以往的定义n[lens][lenp]不同,这次我们选择定义n[lens+1][lenp+1]。这样定义有一个好处,就是不用将首项与中间项进行分开讨论,这里的“ +1 ”实际上相当于在两个字符串之前都先增添了一个相同的项,那接下来只用去讨论包括原来的首项在内的分项即可,无需再进行分类讨论,简化了算法。
最终,总的代码如下:
二、神仙思路:(有幸观看到了两位大佬对此题的解答,惊为天人,故记之)
(一)思路一:在前文中我们已经提到了如何去处理“ * ”的重复次数问题,而我们处理的方法是用两个循环去遍历两个字符串。而第一位大佬,则另辟蹊径,直接将函数当做循环来使用(如当“ * ”重复0次时:isMatch(s,p)=isMatch(s,p+2),即将p+2当做一个新的字符串来使用),但因为没有用二维数组去定义,这里,他选择创建一个新的函数 first_match 来判断首字母是否相同:
不过同时,也因为他定义了这样一个函数,在讨论“ * ”重复一次或是两次及以上时,这两中情况可以进行合并:
最终,整体代码为:
(二)思路二:在上一位大佬思路的基础上,这位大佬选择了将算法更进一步的简化:
他一共只将所有的情况分为了三类:s,p均为空;当s,p均不为空时,p[0]=s[0]或p[0]='.';当p[0]!=s[0]且p[0]!='.',而p[1]='*' 这三种情况。下面我们来依次分析这三种:
1、s,p均为空:这类最简单,直接判断二者是否同时为空即可:
2、s,p均不为空时,p[0]=s[0]或p[0]='.' :此时的p[1]有两种可能,若p[1]='*',那么isMatch(s,p)=isMatch(s+1,p);若p[1]!='*',那么 isMatch(s,p)=isMatch(s+1,p+1):
3、p[0]!=s[0]且p[0]!='.',而p[1]='*':此时 isMatch(s,p)=isMatch(s,p+2):
最终,将三种情况进行并列,得到了最终代码:
return s[0]=='\0'&&p[0]=='\0'||s[0]!='\0'&&p[0]!='\0'&&(p[0]=='.'||p[0]==s[0])&&(p[1]=='*'?isMatch(s +1,p):isMatch(s+1,p+1))||p[0]!='\0'&&p[1]=='*'&&isMatch(s,p+2);