2020.7.18 力扣每日

解法一:暴力法

 1 class Solution {
 2     public boolean isInterleave(String s1, String s2, String s3) {
 3         int index1 = 0, index2 = 0, index3 = 0;
 4         if (check(s1, index1, s2, index2, s3, index3) == true)
 5             return true;
 6         return false;
 7     }
 8     public boolean check(String s1, int index1, String s2, int index2, String s3,int  index3) {
 9         if(index1 == s1.length()) {
10             if (s3.substring(index3).equals(s2.substring(index2)))
11                 return true;
12             else return false;
13         }
14         if(index2 == s2.length()) {
15             if (s3.substring(index3).equals(s1.substring(index1)))
16                 return true;
17             else return false;
18         }
19         if(s1.charAt(index1) == s3.charAt(index3))
20             if (check(s1, index1 + 1, s2, index2, s3, index3 + 1) == true)
21                 return true;
22         if(s2.charAt(index2) == s3.charAt(index3))
23             if (check(s1, index1, s2, index2 + 1, s3, index3 + 1) == true)
24                 return true;
25         return false;
26     }
27 }

解题思路:

    本题中由于字符串是交错组成,ab中又会出现相同的字母,使用双指针的方法,对于样例s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac",就已经出错了。显然这里需要使用别的方法,如回溯,动态规划,递归等。这里就先使用暴力法,即递归所有的可能性,其递归部分与双指针类似,即使用index1,index2,index3记录下当前的指针,分别比较s1与s3,s2与s3在对应位置的字符,相等则使index++,最终遍历完一个字符串时,只需使用substring比较另一个字符串与s3剩下部分即可。

注意点:

    在递归函数中,注意return的时机,如index等于字符串长度时,无论剩余部分是否匹配,都需要return一个值,否则进入后续s1,s2,,s3的字符比较index将越界

递归调用时同样,只有当返回值为true时才return true,否则继续递归遍历其余可能,遍历完所有可能后再return false。

空间复杂度:O(n*m) n,m为s1,s2的长度

时间复杂度:O(2^k), k为s3的长度

题后总结:

优:利用递归,结构易懂清晰,可读性好

差:频繁的递归会有许多重复的操作,时间复杂度太高

解法二:记忆化优化

 1 class Solution {
 2     Boolean[][] mem;
 3     public boolean isInterleave(String s1, String s2, String s3) {
 4         mem = new Boolean[s1.length() + 1][s2.length() + 1];
 5         int index1 = 0, index2 = 0, index3 = 0;
 6         if (check(s1, index1, s2, index2, s3, index3) == true)
 7             return true;
 8         return false;
 9     }
10     public boolean check(String s1, int index1, String s2, int index2, String s3,int  index3) {
11         if (mem[index1][index2] != null)
12             return mem[index1][index2];
13         if (index1 == s1.length()) {
14             if(s3.substring(index3).equals(s2.substring(index2)))
15                 return true;
16             else return mem[index1][index2] = false;
17         }
18         if (index2 == s2.length()) {
19             if (s3.substring(index3).equals(s1.substring(index1)))
20                 return true;
21             else return mem[index1][index2] = false;
22         }
23         if (s1.charAt(index1) == s3.charAt(index3))
24             if (check(s1, index1 + 1, s2, index2, s3, index3 + 1) == true)
25                 return true;
26         if (s2.charAt(index2) == s3.charAt(index3))
27             if (check(s1, index1, s2, index2 + 1, s3, index3 + 1) == true)
28                 return true;
29         return mem[index1][index2] =false;
30     }
31 }

解题思路:

    依旧使用递归遍历所有可能性,但对于递归,一般都可使用记忆化的方式来优化时间复杂度,显然此处也可以,设置一个mem数组记录递归的结果,每次进入递归只需判断对应mem的状态,可减少重复操作,该题中显然mem数组的大小可以设置为s1与s2的长度。

注意点:

    由于mem记录的是所有的可能性,范围为[0,length],所以定义时数组长度应定义为length()+1

    由于每次需判断对应mem的状态,若定义为boolean类型数组,则初值默认为false,无法满足需求,此处需定义为Boolean类型,这样初值便为null,可以通过if条件判断来减少重复操作。

空间复杂度:O(n*m)

时间复杂度:O(n*m) n,m为s1,s2的长度

题后总结:

优:在递归的基础上使用了记忆化优化,减小了时间复杂度

差:代码仍有些臃肿,还可更简化些。

碎碎念:不过这是第一次这么顺利解决困难难度的题目!而且优化了时间复杂度!全靠自己,快而准确!开心

 

posted @ 2020-07-18 22:52  小小码农-安  阅读(206)  评论(0编辑  收藏  举报