不重复字符

时间:2017-01-07 18:51:18

标签: java longest-substring

鉴于" 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,但我不能概念化它为什么能给我们预期的结果;有人可以向我解释这一步,特别是为什么它有效?

2 个答案:

答案 0 :(得分:2)

我通常不善于解释,让我通过考虑一个例子来试一试。

字符串是&#34; wcabcdeghi&#34;。

忘记代码一分钟,并假设我们正试图提出一个逻辑。

  1. 我们从w开始继续前进,直到我们到达c - &gt; a - &gt; b - &gt;角
    我们需要在此时停止,因为&#34; c&#34;正在重复。因此,如果重复一个角色,我们需要一个地图来存储。 (代码: map.put(currentChar, i);
  2. 现在我们知道一个角色是否重复,我们需要知道什么是最大值。到目前为止。 (代码 - max
  3. 现在我们知道跟踪前两个变量w-> c的计数是没有意义的。这是因为包括这个,我们已经得到了Max。值。因此,从下一次迭代开始,我们只需要从 - &gt;检查长度。 b - &gt;不久。
    让我们有一个变量(代码 - startingIndexOfLongestSubstring来跟踪这一点。 (这应该被命名为startingIndexOfNonRepetativeCharacter,然后我再次命名也不好。)
  4. 现在我们再次继续,但等待我们仍然没有最终确定如何跟踪我们当前正在解析的子字符串。 (即来自abcd ......)
    想到这一点,我所需要的只是在哪里&#34; a&#34;存在(这是startingIndexOfNonRepetativeCharacter)因此要知道当前子字符串的长度我需要做的是(代码 - i - startingIndexOfLongestSubstring + 1(当前字符位置 - 非重复字符长度+(减法不包括双方所以加1)。让我们称之为currentLength
  5. 但是等一下,我们该怎么办呢。每次我们找到一个新变量时,我们都需要检查这个currentLength是否会破坏我们的最大值。 所以(代码 - max = Math.max(max, i - startingIndexOfLongestSubstring + 1);
  6. 现在我们已经涵盖了我们需要的大部分陈述,并且根据我们的逻辑,每当我们遇到一个已经存在的变量时,我们所需要的只是startingIndexOfLongestSubstring = map.get(currentChar)。那我们为什么要做Max呢? 考虑一下String是&#34; wcabcdewghi&#34;的场景。当我们开始处理我们的新计数器时 - > b - &gt; c - &gt; d - &gt; e - &gt; w 此时我们的逻辑检查此字符是否先前存在。从它现在开始,它从索引&#34; 1&#34;开始计数。这完全扰乱了整个计数。所以我们需要确定,我们从map中获取的下一个索引总是大于我们计数的起始点(即,只有当字符出现在startingIndexOfLongestSubstring之前时才从地图中选择一个字符。)
  7. 希望我已经回答了代码中的所有行,主要是如果解释是可以理解的。

答案 1 :(得分:1)

因为

i - startingIndexOfLongestSubstring + 1

istartingIndexOfLongestSubstring索引之间的字符数。例如,位置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;

    }
}