Java 函数在某些情况下工作,但当最长子字符串;重复使用;人物

Java 函数在某些情况下工作,但当最长子字符串;重复使用;人物,java,linked-list,Java,Linked List,我有一个名为lengthOfLongestSubstring的函数,它的工作是查找最长的子字符串,而不包含任何重复字符。在大多数情况下,它是有效的,但当它得到像“dvdf”这样的输入时,它会打印出2(而不是3),并在应该是[d,vdf]时给出[dv,df] 因此,我首先检查字符串,看看是否有唯一的字符。如果有,我将其附加到ans变量。(我认为这是需要修理的部分)。如果有重复的字符串,我将其存储在子字符串链表中,并将ans变量重置为重复字符串 遍历整个字符串后,我找到最长的子字符串并返回其长度 p

我有一个名为lengthOfLongestSubstring的函数,它的工作是查找最长的子字符串,而不包含任何重复字符。在大多数情况下,它是有效的,但当它得到像“dvdf”这样的输入时,它会打印出2(而不是3),并在应该是[d,vdf]时给出[dv,df]

因此,我首先检查字符串,看看是否有唯一的字符。如果有,我将其附加到ans变量。(我认为这是需要修理的部分)。如果有重复的字符串,我将其存储在子字符串链表中,并将ans变量重置为重复字符串

遍历整个字符串后,我找到最长的子字符串并返回其长度

public static int lengthOfLongestSubstring(String s) {    
    String ans = "";
    int len = 0;
    LinkedList<String> substrings = new LinkedList<String>(); 
    for (int i = 0; i < s.length(); i++) {
      if (!ans.contains("" + s.charAt(i))) {
        ans += s.charAt(i);
      } else {
        substrings.add(ans);
        ans = "" + s.charAt(i);
      }
    }

    substrings.add(ans); // add last seen substring into the linked list

    for (int i = 0; i < substrings.size(); i++) {
      if (substrings.get(i).length() >= len)
        len = substrings.get(i).length();
    }

    System.out.println(Arrays.toString(substrings.toArray()));

    return len;


}


有什么建议可以解决这个问题吗?我必须重做我所有的逻辑吗


谢谢

而不是在找到字符匹配时将
ans
设置为当前字符

ans = "" + s.charAt(i);
您应该将当前字符添加到当前字符第一次匹配后的所有字符中

ans = ans.substring(ans.indexOf(s.charAt(i)) + 1) + s.charAt(i);
因此,完整的方法成为

    public static int lengthOfLongestSubstring(String s) {
        String ans = "";
        int len = 0;
        LinkedList<String> substrings = new LinkedList<>();
        for (int i = 0; i < s.length(); i++) {
            if (!ans.contains("" + s.charAt(i))) {
                ans += s.charAt(i);
            } else {
                substrings.add(ans);
                // Only the below line changed
                ans = ans.substring(ans.indexOf(s.charAt(i)) + 1) + s.charAt(i);
            }
        }

        substrings.add(ans); // add last seen substring into the linked list

        for (int i = 0; i < substrings.size(); i++) {
            if (substrings.get(i).length() >= len)
                len = substrings.get(i).length();
        }

        System.out.println(Arrays.toString(substrings.toArray()));

        return len;
    }

而不是在找到字符匹配时将
ans
设置为当前字符

ans = "" + s.charAt(i);
您应该将当前字符添加到当前字符第一次匹配后的所有字符中

ans = ans.substring(ans.indexOf(s.charAt(i)) + 1) + s.charAt(i);
因此,完整的方法成为

    public static int lengthOfLongestSubstring(String s) {
        String ans = "";
        int len = 0;
        LinkedList<String> substrings = new LinkedList<>();
        for (int i = 0; i < s.length(); i++) {
            if (!ans.contains("" + s.charAt(i))) {
                ans += s.charAt(i);
            } else {
                substrings.add(ans);
                // Only the below line changed
                ans = ans.substring(ans.indexOf(s.charAt(i)) + 1) + s.charAt(i);
            }
        }

        substrings.add(ans); // add last seen substring into the linked list

        for (int i = 0; i < substrings.size(); i++) {
            if (substrings.get(i).length() >= len)
                len = substrings.get(i).length();
        }

        System.out.println(Arrays.toString(substrings.toArray()));

        return len;
    }

您的代码错误地假设,当您找到一个重复的字符时,下一个候选子字符串从该重复的字符开始。这不是真的,它从原始角色之后开始

示例:如果字符串是
“abcXdefXghiXjkl”
,则有3个候选子字符串:
“abcXdef”
“defXghi”
,和
“ghiXjkl”

如您所见,候选子字符串在重复字符之前结束,在重复字符之后开始(以及字符串的开始和结束)

因此,当您找到一个重复字符时,需要该字符的上一个实例的位置来确定下一个候选子字符串的开始

处理这个问题最简单的方法是,将角色映射到最后一次看到的位置。这也将比持续执行子字符串搜索来检查重复字符的速度更快,就像问题代码和其他答案所做的那样

大概是这样的:

public static int lengthOfLongestSubstring(String s) {
    Map<Character, Integer> charPos = new HashMap<>();
    List<String> candidates = new ArrayList<>();
    int start = 0, maxLen = 0;
    for (int idx = 0; idx < s.length(); idx++) {
        char ch = s.charAt(idx);
        Integer preIdx = charPos.get(ch);
        if (preIdx != null && preIdx >= start) { // found repeat
            if (idx - start > maxLen) {
                candidates.clear();
                maxLen = idx - start;
            }
            if (idx - start == maxLen)
                candidates.add(s.substring(start, idx));
            start = preIdx + 1;
        }
        charPos.put(ch, idx);
    }
    if (s.length() - start > maxLen)
        maxLen = s.length() - start;
    if (s.length() - start == maxLen)
        candidates.add(s.substring(start));
    System.out.print(candidates + ": ");
    return maxLen;
}
试验

输出(带有候选列表)


您的代码错误地假设,当您找到一个重复的字符时,下一个候选子字符串从该重复的字符开始。这不是真的,它从原始角色之后开始

示例:如果字符串是
“abcXdefXghiXjkl”
,则有3个候选子字符串:
“abcXdef”
“defXghi”
,和
“ghiXjkl”

如您所见,候选子字符串在重复字符之前结束,在重复字符之后开始(以及字符串的开始和结束)

因此,当您找到一个重复字符时,需要该字符的上一个实例的位置来确定下一个候选子字符串的开始

处理这个问题最简单的方法是,将角色映射到最后一次看到的位置。这也将比持续执行子字符串搜索来检查重复字符的速度更快,就像问题代码和其他答案所做的那样

大概是这样的:

public static int lengthOfLongestSubstring(String s) {
    Map<Character, Integer> charPos = new HashMap<>();
    List<String> candidates = new ArrayList<>();
    int start = 0, maxLen = 0;
    for (int idx = 0; idx < s.length(); idx++) {
        char ch = s.charAt(idx);
        Integer preIdx = charPos.get(ch);
        if (preIdx != null && preIdx >= start) { // found repeat
            if (idx - start > maxLen) {
                candidates.clear();
                maxLen = idx - start;
            }
            if (idx - start == maxLen)
                candidates.add(s.substring(start, idx));
            start = preIdx + 1;
        }
        charPos.put(ch, idx);
    }
    if (s.length() - start > maxLen)
        maxLen = s.length() - start;
    if (s.length() - start == maxLen)
        candidates.add(s.substring(start));
    System.out.print(candidates + ": ");
    return maxLen;
}
试验

输出(带有候选列表)


创建嵌套for循环以在数组中的每个索引处进行检查

    public static int lengthOfLongestSubstring(String s) {    
    String ans = "";
    int len = 0;
    LinkedList<String> substrings = new LinkedList<String>();
    int k = 0;
    for (int i = 0; i < s.length(); i++) {
        if(k == s.length()) {
            break;
        }
        for(k = i; k < s.length(); k++) {
          if (!ans.contains("" + s.charAt(k))) {
            ans += s.charAt(k);
          } else {
            substrings.add(ans);
            ans = "";
            break;
          }
        }
    }

    substrings.add(ans); // add last seen substring into the linked list

    for (int i = 0; i < substrings.size(); i++) {
      if (substrings.get(i).length() >= len)
        len = substrings.get(i).length();
    }

    System.out.println(Arrays.toString(substrings.toArray()));

    return len;

}

创建嵌套for循环以在数组中的每个索引处进行检查

    public static int lengthOfLongestSubstring(String s) {    
    String ans = "";
    int len = 0;
    LinkedList<String> substrings = new LinkedList<String>();
    int k = 0;
    for (int i = 0; i < s.length(); i++) {
        if(k == s.length()) {
            break;
        }
        for(k = i; k < s.length(); k++) {
          if (!ans.contains("" + s.charAt(k))) {
            ans += s.charAt(k);
          } else {
            substrings.add(ans);
            ans = "";
            break;
          }
        }
    }

    substrings.add(ans); // add last seen substring into the linked list

    for (int i = 0; i < substrings.size(); i++) {
      if (substrings.get(i).length() >= len)
        len = substrings.get(i).length();
    }

    System.out.println(Arrays.toString(substrings.toArray()));

    return len;

}

您的问题是,在
ans=”“+s.charAt(i)
行上,您假设要录制的下一个字符串从当前字符开始。您应该将
ans
设置为前一个
ans
,但不包含其第一个字符,再加上
charAt(i)
。您的问题是,在
ans=”“+s.charAt(i)
行上,您假设要录制的下一个字符串从当前字符开始。您应该将
ans
设置为前一个
ans
,不带第一个字符,加上
charAt(i)
lengthOfLongestSubstring("ABDEFGABEF"); -> 6 ([ABDEFG, BDEFGA, DEFGAB, EFGAB, FGABE, GABEF])