鉴于" abcabcbb",答案为" abc",长度为3。
鉴于" bbbbb",答案为" b",长度为1。
鉴于" pwwkew",答案为" wke",长度为3.注意答案必须是子字符串," pwke&#34 ;是子序列而不是子字符串。
我想出了一个有效的解决方案,但在几个测试用例中失败了。然后我找到了一个更好的解决方案,并重写了它以尝试理解它。下面的解决方案完美无瑕,但经过大约2个小时的战斗,我仍然无法理解为什么这个特定的代码行有效。
import java.util.*;
import java.math.*;
public class Solution {
public int lengthOfLongestSubstring(String str) {
if(str.length() == 0)
return 0;
HashMap<Character,Integer> map = new HashMap<>();
int startingIndexOfLongestSubstring = 0;
int max = 0;
for(int i = 0; i < str.length(); i++){
char currentChar = str.charAt(i);
if(map.containsKey(currentChar))
startingIndexOfLongestSubstring = Math.max(startingIndexOfLongestSubstring, map.get(currentChar) + 1);
map.put(currentChar, i);
max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
}//End of loop
return max;
}
}
有问题的行是
max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
我不明白为什么会这样。我们在前一个max和我们当前索引与当前最长子字符串的起始索引之间的差值然后加1之间取最大值。我知道代码正在获得当前索引之间的差异,和startingIndexOfSubstring,但我不能概念化它为什么能给我们预期的结果;有人可以向我解释这一步,特别是为什么它有效?
答案 0 :(得分:2)
我通常不善于解释,让我通过考虑一个例子来试一试。
字符串是&#34; wcabcdeghi&#34;。
忘记代码一分钟,并假设我们正试图提出一个逻辑。
map.put(currentChar, i);
)max
startingIndexOfLongestSubstring
来跟踪这一点。 (这应该被命名为startingIndexOfNonRepetativeCharacter,然后我再次命名也不好。)startingIndexOfNonRepetativeCharacter
)因此要知道当前子字符串的长度我需要做的是(代码 - )i - startingIndexOfLongestSubstring + 1
(当前字符位置 - 非重复字符长度+(减法不包括双方所以加1)。让我们称之为currentLength
currentLength
是否会破坏我们的最大值。
所以(代码 - )max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
startingIndexOfLongestSubstring = map.get(currentChar)
。那我们为什么要做Max
呢?
考虑一下String是&#34; wcabcdewghi&#34;的场景。当我们开始处理我们的新计数器时 - > b - &gt; c - &gt; d - &gt; e - &gt; w 此时我们的逻辑检查此字符是否先前存在。从它现在开始,它从索引&#34; 1&#34;开始计数。这完全扰乱了整个计数。所以我们需要确定,我们从map中获取的下一个索引总是大于我们计数的起始点(即,只有当字符出现在startingIndexOfLongestSubstring
之前时才从地图中选择一个字符。)希望我已经回答了代码中的所有行,主要是如果解释是可以理解的。
答案 1 :(得分:1)
因为
i - startingIndexOfLongestSubstring + 1
是i
和startingIndexOfLongestSubstring
索引之间的字符数。例如,位置2和3之间有多少个字符? 3-2=1
但我们有2个字符:位置2和位置3。
我已经描述了代码中的每个操作:
public class Solution {
public int lengthOfLongestSubstring(String str) {
if(str.length() == 0)
return 0;
HashMap<Character,Integer> map = new HashMap<>();
int startingIndexOfLongestSubstring = 0;
int max = 0;
// loop over all characters in the string
for(int i = 0; i < str.length(); i++){
// get character at position i
char currentChar = str.charAt(i);
// if we already met this character
if(map.containsKey(currentChar))
// then get maximum of previous 'startingIndexOfLongestSubstring' and
// map.get(currentChar) + 1 (it is last occurrence of the current character in our word before plus 1)
// "plus 1" - it is because we should start count from the next character because our current character
// is the same
startingIndexOfLongestSubstring = Math.max(startingIndexOfLongestSubstring, map.get(currentChar) + 1);
// save position of the current character in the map. If map already has some value for current character
// then it will override (we don't want to know previous positions of the character)
map.put(currentChar, i);
// get maximum between 'max' (candidate for return value) and such value for current character
max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
}//End of loop
return max;
}
}