题目描述
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
示例1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3:
输入: "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是子串的长度,"pwke" 是一个子序列,不是子串。
题目解答
可以用动态规划的思路解答。
依次计算以下标为i的字符结尾的不包含重复字符的子字符串的最长长度。
如果第i个字符之前没有出现过,则f(i)=f(i-1)+1。
如果出现过,则分两种情况讨论。先计算第i个字符和它上次出现在字符串中的位置的距离,记为d。
第一种情况:d小于等于f(i-1),则重复字符出现在f(i-1)的子字符串中,f(i)=d。
第二种情况:d大于f(i-1),则重复字符出现在f(i-1)的子字符串之前,f(i)=f(i-1)+1。
伪代码:
for i=0 to i=s.length
if 第i个字符没有出现过
f(i)=f(i-1)+1
endif
else
计算d
if(d<=f(i-1))
f(i)=d
endif
else
f(i)=f(i-1)+1
end
end
end
关键在于:
1.如何判断第i个字符是否出现过;
2.如何计算d,即第i个字符和它上次出现在字符串中的位置的距离。
关于问题1,在JS中有一个关于字符串的方法indexOf(),可以返回某字符在字符串中首次出现的索引值,若未出现过则返回-1。
另一个方法lastIndexOf(),返回的是某字符在字符串中最后出现的索引值。
在该题的情况下,应该选用lastIndexOf()比较合适。
所以可以通过以下代码对问题进行判断:
if(s.substring(0,i).lastIndexOf(s[i])>-1)
则字符串s(索引0~i-1)中包含字符s[i]
注意!!!
不能用if(s.substring(0,i-1).lastIndexOf(s[i]))判断,虽然没有字符出现在字符串中返回的是-1,但是直接用if判断上述语句,返回的还是true。
最终实现:
var lengthOfLongestSubstring = function(s) {
if(s.length<=0){
return 0;
}
var resultStringLength = 1; //f(0)=1
var resultOfEveryIndex = 1;
var d = 0;
for(var i=1;i<s.length;i++){
// 从f(1)开始计算
// 如果第i个字符之前出现过
var index = s.substring(0,i).lastIndexOf(s[i]);
if(index>-1)
{
d = i - index;
if(d<=resultOfEveryIndex){
resultOfEveryIndex = d;
}else{
resultOfEveryIndex++;
}
}else{
resultOfEveryIndex++;
}
if(resultOfEveryIndex>resultStringLength){
resultStringLength = resultOfEveryIndex;
}
}
return resultStringLength;
};