本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目描述【easy】
解题思路
1.初见
本题的题意比较清晰明了,给定字符串,找出相同字符之间的最长子字符串的长度,思路比较清晰:遍历字符串,首次遍历到的字符X记录其位置startPos,继续遍历遇到X字符,计算字符X间子字符串长度,字符X可能有多个,保留最大值即可,多个不同字符间最长子字符串中最大值即为结果。
代码-1.初见
public int maxLengthBetweenEqualCharacters(String s) {
int len = s.length();
if (len <= 1) {
return 0;
}
int maxLen = -1;
// 记录字符首次出现的位置
Map<Character, Integer> frequencyMap = new HashMap<>();
for (int index = 0; index < len; ++index) {
char ch = s.charAt(index);
if (frequencyMap.containsKey(ch)) {
// 更新满足题目要求的字符间最长子字符串长度
int curLen = index - frequencyMap.get(ch) - 1;
maxLen = curLen > maxLen ? curLen : maxLen;
} else {
frequencyMap.put(ch, index);
}
}
return maxLen;
}
- 时间复杂度:O(N)
- 空间复杂度:O(N)~O(1)
2.探索
上述「1.初见」思路比较明显,实现中采用HashMap进行存储,做到O(1)时间复杂度确定字符X首次出现的位置startPos,题中给出的提示:输入字符串中只包含小写字母,可以进一步简化代码剔除HashMap,借用数组实现HashMap的快速查找能力。
代码-2.探索【伪代码】
// 数组记录字符首次出现位置 X∈[a~z]
int[] posArr = new int[26]; // init with -1
for ch in str
if posArr[ch - 'a'] != -1
posArr[ch - 'a'] = pos(ch);
else
do update maxLen
- 时间复杂度:O(N)
- 空间复杂度:O(26)≈O(1)
3.归途
本地题意清晰,无需多言,这里聊一下LeetCode或者说工程上常用的一种降低时间复杂度的方式,空间换时间,就本题来说,直接使用暴力求解:两层for循环进行遍历计算两个相同字符间最长子字符串,暴力求解的时间复杂度为O(N^2);空间换时间,使用长度26的数组或HashMap,可以将算法的耗时下降2个量级,整体来看收益巨大。
空间换时间
- 原理:最早了解到的空间换时间的原理是局部性原理,简单理解就是:90%(maybe)的请求量集中在10%的数据上,通过引入缓存
Cache的方式,「见封面图」,降低整体的访问耗时--即时间复杂度; - 应用:工程上实际业务场景,
Redis、MemCache、CDN、JIT...之类都是应用局部性原理;局部性原理更多了解; - 此处应用:由于进行遍历时,程序是无状态的,通过记录遍历过程中的一些状态,剪枝遍历的次数,大大提升了程序的性能,也是局部性原理的一种应用。
4.拓展
本题题意清晰,进一步分析,想到连连看小游戏,本题本质上是寻找任意两个相同字符,其间隔的长度最大;进一步拓展,可以考虑如下的题目:
小羊最近新下载了一个游戏叫“LeetCode连连看”,游戏玩法如下,给定连连看字符串str="abbadaccda",小羊需要对字符串进行连线,进行连线时两个相同字符中的子字符串长度为消耗的能量数,连线之后的字符从字符串中剔除,直到连线完所有可以连接的字符,游戏结束,消耗能量数越少获得奖励越多,请jy们帮小羊获得最大奖励吧!
case1:
str = "abbadaccda"
最优连线方式为:bb、aa、cc、dd、aa,消耗能量数为:1(连线dd时子字符串长度为1)