思路一:(该解法面对最后的大字符串[31000个字符]会超时)
- 因为题目中要求取不存在重复字符的最大字符串,第一想法是想理解成贪心问题,总的长度为n,判断k个格子的不重复子字符串是否存在。如求取当1个字符长度的不重复字符串是否存在;2个字符长度的不重复字符串是否存在;3个字符长度的不重复字符串是否存在...n个字符长度的不重复字符串是否存在
代码如下:
// 再次提醒,该解法不能完全解出题目,最后一个大字符串用例因为超时无法通过,仅提供一种实现思路
class Solution {
public int lengthOfLongestSubstring(String s) {
// 思路借鉴动态规划划格子方法
int len = s.length();
if (len == 0) return 0;
int max = 1;
// 最小的格子 1 到最大的格子 len
for (int i = 1 ; i <= len ; i++) {
// 判断该格子下的不重复子字符串是否存在
for(int start = 0; start <= len - i; start ++ ) {
char[] copy = new char[i];
s.getChars(start, start + i,copy,0);
if(unRepeat(copy)) {
max = i;
break;
}
}
}
return max;
}
// 重复返回false
boolean unRepeat(char[] chars) {
Set s = new HashSet();
for (char ch: chars) {
if(!s.contains(ch)) {
s.add(ch);
} else {
return false;
}
}
return true;
}
}
思路二(正规题解)
使用滑动窗口解决问题
- 设置变量记录滑动过程中的子字符串最大值
- 该字符串最长子串是不定变化的,因此在遇到重复字符串的时候需要修改滑动窗口的大小,即把窗口的最左边界进行调整
- 调整的方法是将left边界值调整到Max(left,重复子字符串位置 + 1),因为窗口中如果包含该字符串则说明窗口中存在重复,需要收缩窗口的左边界
- 然后窗口不断的向右遍历到最后一个字符
- 为了快速查到是否为重复的字符串使用hashmap来记录,字符和字符位置,遇到相同字符的时候需要更新字符位置
class Solution {
public int lengthOfLongestSubstring(String s) {
// 1. 设置变量记录最大值
// 2. 遇到重复字符串的时候调整窗口边界
// 3. 遍历处理到字符串的最右边
// 4. 使用map记录字符串和字符串位置
// 字符串长度
int len = s.length();
int left = 0; // 左窗口
int right = 0; // 右窗口
int max = 0; // 最长子串
// 记录字符和字符位置
Map<Character,Integer> charMap = new HashMap<>();
while (right < len) {
if(charMap.containsKey(s.charAt(right))) {
// 这里使用Math.max是因为可能会发生新发现的重复字符在map中存储的位置在窗口最左边界外
left = Math.max(left,charMap.get(s.charAt(right)) + 1);
}
// 更新字符位置
charMap.put(s.charAt(right), right);
max = Math.max(max, right - left + 1);
// 滑动右窗口
right++;
}
return max;
}
}
解法二就十分的简洁明了,好的算法好重要,效率上差距好大🥺
Q.E.D.