这是中等题?
1、先读题
读完题的第一想法是——介尼玛是中等题?
2、审题
题目简单明了,且没有什么陷阱。
要说重点,似乎也没有什么重点。
毕竟我只想出了暴力。
总之,让我们直接快进到思路吧。
3、思路
我第一时间就想到了,这题肯定有简单的数学公式可以使用。但无奈,此时的我已经根本想不起来KMP算法了。
顺着题意我们肯定会想到,只要我们重复拼接字符串a,在逐步去判断b是否是新字符串的子串的话,这题就能迎刃而解了。
事实证明,这种基于暴力的简单直接的想法是可行的,当然耗时排名就没那么好看了。
于是,在基于暴力解决此题的思路下,我们面临了如下要点:
- 如何确认b必不可能是a的子串?
- 如何控制字符串a拼接的次数?
基于问题1,我们可以依次读取b字符串中的所有字符,并判断有没有a中不存在的字符。这种想法很容易实现,但出于耗时问题,就直接被我抛弃了。毕竟,在判断b是否为a的拼接字符串的子串过程中,就囊括了这个问题。
那么问题2呢?在我脑海里,是计划使用循环来控制拼接a字符串。于是这个问题也就变成了——如何控制跳出循环?
我们来思考下如果b是a重复0~N次后的字符串的子串时,b会有哪些情况:
- 如果
b.length()<= a.length()
时,则b应该是a[i:end]+a[0:j]
的情况。此时的答案显然是2。 - 如果
b.length()>a.length()
时,则b应该是a[i:end]+ N* a +a[0:j]
的情况。此时的答案是N+2。
就如上两种情况,从第2条我们可以发现,a的重复字符的长度超过b后,最多还需要再拼接2次。如果2次还不行,辣么在多次都不可能实现,应当返回-1。
于是思路在此成型。
4、撸代码
class Solution {
public int repeatedStringMatch(String a, String b) {
StringBuilder sb = new StringBuilder(a);
int ans = 1;
while (sb.length() <= b.length() + 2 * a.length()) {
if (sb.length() >= b.length() &&
sb.toString().contains(b)) {
return ans;
}
sb.append(a);
++ans;
}
return -1;
}
}
5、解读
就同我在思路中所说,我以StringBuilder来拼接字符串a,并且每次拼接后,都判断一下b是否是其子串。
if (sb.length() >= b.length() &&
sb.toString().contains(b)) {
return ans;
}
如果是的话,此时的ans
便是答案对应的循环次数。
当循环跳出,仍然没有得到匹配子串成功的话,说明无法得出结果,即返回-1。
6、提交
因为是暴力,这种耗时排名甚至比预期还要高。
看来用暴力的人挺多的啊
7、咀嚼
啊这,这个该怎么分析啊……
8、受益匪浅
就如我先头所说,读完题我就知道了会有数学的解法,于是提交完暴力就直接跑去点题解了。
今天的题可以学的可太多了,首先是官解提供的两种算法——Rabin-Karp 算法 和 Knuth-Morris-Pratt 算法。
后者就是KMP了,这个我在大一时就学会,并一度用来刷过很多题的算法。然后……若干年的工作后,就忘得一干二净了。
毕竟大部分的业务场景都不会接触到这些东西……
曾经陪伴你的知识,就这样一点点被遗忘了。
不过忘了就再捡起来嘛!
当然,除了牛逼的公式算法,还有其他大牛分享的解法。
其核心思路也与我的有异曲同工之妙,但有更优秀更值得学习的点。
9、总结
俗话说——黑猫白猫抓到耗子的就是好猫。
牛逼算法暴力解法,能够做出题目的都是好解法。
虽然今天的题我只能基于思路做出优化的暴力解法,但这种朴实无华的解法,能够让我在自己规定的时限内做出题目,也8是8行。
然后,官解的两种算法也很值得学习(算法的核心就是数学啊 ),对于这种公式化的数学算法,学会了往往能举一反三,一招刷遍所有类似的题。
啊……好忙……
社畜不想努力了,有没有富婆可以包养我啊……