题目描述:
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given abcabcbb
, the answer is abc
, which the length is 3.
Given bbbbb
, the answer is b
, with the length of 1.
Given pwwkew
, the answer is wke
, with the length of 3. Note that the answer must be a substring, pwke
is a subsequence and not a substring.
给定一个字符串,找出不含有重复字符的最长子串的长度。
示例:
给定 abcabcbb
,没有重复字符的最长子串是 abc
,那么长度就是3。
给定 bbbbb
,最长的子串就是 b
,长度是1。
给定 pwwkew
,最长子串是 wke
,长度是3。请注意答案必须是一个子串,pwke
是 子序列 而不是子串。
解法一(Sliding Window):
首先将 t 中的所有字符出现次数记录到整形数组 hash 中,然后设置一个 counter 代表与 t 中字符的差异度。在 s 右移的过程中,一旦发现当前字符出现在 t 中(hash中对应的值大于 0),就将差异度减一,直到差异度为 0 时,说明找到了一个子串,它匹配所有 t 中的字符。将该子串与之前记录的相比,更新短的子串。之后将窗口左边界右移,判断移出窗口的字符是否在 t 中,如果存在则将差异度加一,否则无须处理。
最后,当右边界到达最右端时,可以结束循环,因为左边界处的元素必定是存在在 t 中的,如果此时还将左边界的元素移出的话,那么最短的子串必定不在剩余的子串中了,所以可以直接结束循环。
public String minWindow(String s, String t) {
int[] hash = new int[256];
for (char c : t.toCharArray())
hash[c] ++;
int counter = t.length(); // 与t中字符的差异度
int l = 0;
int r = 0;
int min = s.length() + 1;
String res = "";
while (r < s.length()) {
if (hash[s.charAt(r++)] -- > 0)
counter --;
while (counter == 0) { // 说明已经找到
if (min > r-l) { // 找到更短的子串
min = Math.min(min, r - l);
res = s.substring(l, r);
}
// 说明此字符存在在t中
if (hash[s.charAt(l++)] ++ == 0)
counter ++; // 变为不可用
}
}
return res;
}
通用模板:
很多子串的问题,都是需要满足一些限制条件,因此有大神给出了一套模板,这里借鉴一下,欣赏一下大神优雅的思路。
public int findSubstring(string s){
vector<int> map(128,0);
int counter; // 检查子串是否匹配条件
int begin=0, end=0; // 头尾指针
int d; //子串的长度
for() { /* 初始化 hash 数组或者 Map */ }
while(end<s.size()){
if(map[s[end++]]-- ?){ /* 更新 counter */ }
while(/* counter 条件判断 */){
/* 如果找到了更小子串则更新 d */
// 增加 begin 指针,使得子串再次可用/不可用,也就是需要再向右前进才能找到其他的匹配
if(map[s[begin++]]++ ?){ /* 更新 counter */ }
}
/* 如果找到了更大子串则更新 d */
}
return d;
}
需要注意的是,如果题意取的是最大子串,我们需要再 while 循环的外面进行更新操作;如果取的是最小子串,则要在 while 内层循环里进行更新操作。
关于最大子串的情况,可以参考每日一恋 - LeetCode 3. Longest Substring Without Repeating Characters(无重复字符的最长子串)
参考:
Here is a 10-line template that can solve most ‘substring’ problems
原题链接