Java 最长的子字符串,超过了时间限制

Java 最长的子字符串,超过了时间限制,java,string,algorithm,Java,String,Algorithm,给定一个字符串,查找最长子字符串的长度,不重复字符。例如,“abcabcbb”不重复字母的最长子字符串是“abc”,其长度为3。对于“bbb”,最长的子字符串是“b”,长度为1 public static int lengthOfLongestSubstring(String s) { if (s.length()==0) return 0; int maxlen = 1; HashMap<Character, ArrayList<Integ

给定一个字符串,查找最长子字符串的长度,不重复字符。例如,“abcabcbb”不重复字母的最长子字符串是“abc”,其长度为3。对于“bbb”,最长的子字符串是“b”,长度为1

public static int lengthOfLongestSubstring(String s) {
    if (s.length()==0)
        return 0;
    int maxlen = 1;

    HashMap<Character, ArrayList<Integer>> check = new HashMap<Character,ArrayList<Integer>>();
    for (int i = 0; i < s.length(); i++) {
        for (int j = i; j < s.length(); j++) {
            if (!check.containsKey(s.charAt(j))) {
                ArrayList<Integer> value= new ArrayList<>();
                value.add(j);
                check.put(s.charAt(j), value);
            }
            else {
                maxlen = Math.max(j - i, maxlen);
                ArrayList<Integer> temp = check.get(s.charAt(j));
                i=temp.get(temp.size()-1);  
              // get the last index(biggest index) of the key value
                check.clear();
                break;
            }
            if(j==s.length()-1) {
                maxlen = Math.max(j - i + 1, maxlen);
            }

        }
    }
    return maxlen;
  }
}
public static int lengthOfLongestSubstring(字符串s){
如果(s.length()==0)
返回0;
int maxlen=1;
HashMap check=新建HashMap();
对于(int i=0;i

对于长可重复字符串的最后一次测试,超出了时间限制。不知道如何优化。寻求改进,谢谢

这个问题可以用O(N)来解决,其中N是字符串的长度

算法:

1) 迭代字符串中的字符。跟踪每个字符的最后一次出现。在每个信件商店,前一个相同的字符离我们有多远。 例如:使用字符串“abccdae”,我们将得到列表[1,2,3,1,5,5,7]。请注意,如果字符在我们将其设置为单词开头的长度之前没有出现

2) 让我们调用我们得到的列表V(在示例V=[1,2,3,1,5,5,7])

3) 定义函数f(x),它计算不重复以索引x结尾的字符的最长单词

它认为: f(0)=0 f(x)=min(f(x-1)+1,V[x]),x>0

4) 迭代word并在每个索引处计算f

5) 求f的最大值

每一步都是O(N),但如果你到处玩,你可以同时完成所有的步骤,甚至可以不断提高


希望这有帮助。

在下面找到一个优化的版本。与初始版本相比的增强功能:

  • 它不会创建其他对象
  • 它不复制任何字符,它处理字符串数据本身
  • 它减少了比较步骤的数量
edit2我上传了一个JMH基准测试,它比较了这个问题的三个答案的算法。直接链接到


编辑如Boris所述,仍有可能进行优化。在这里,我将不遵循Donald E.Knuth的观点:“过早优化是万恶之源。”;-)

这里有一个相当简单的解决方案,它应该比您的解决方案更快:

public static int longestNonRepeating(final String s) {
    final Set<Character> unique = new HashSet<>();
    int max = 0;
    for (int i = 0; i < s.length(); ++i) {
        final char c = s.charAt(i);
        if (!unique.add(c)) {
            for (int j = i - unique.size(); j < i; ++j) {
                if (s.charAt(j) != c) {
                    unique.remove(s.charAt(j));
                } else {
                    break;
                }
            }
        }
        max = Math.max(max, unique.size());
    }
    return max;
}
在我们独特的
集合中有
a

a  b  c  a  b  c
0  1  2  3  4  5
   ^
   |
   i
a  b  c  a  b  c
0  1  2  3  4  5
      ^
      |
      i
a  b  c  a  b  c
0  1  2  3  4  5
^        ^
|        |
j        i
在我们独特的
集合中有
a、b

a  b  c  a  b  c
0  1  2  3  4  5
   ^
   |
   i
a  b  c  a  b  c
0  1  2  3  4  5
      ^
      |
      i
a  b  c  a  b  c
0  1  2  3  4  5
^        ^
|        |
j        i
在我们独特的
集合中有
a、b、c

a  b  c  a  b  c
0  1  2  3  4  5
   ^
   |
   i
a  b  c  a  b  c
0  1  2  3  4  5
      ^
      |
      i
a  b  c  a  b  c
0  1  2  3  4  5
^        ^
|        |
j        i
我们尝试将
添加到唯一的
集合
,它是重复的。从唯一子字符串的开头,尝试查找
a
。幸运的是,这是在
0
,我们不需要从unique中删除任何内容

a  b  c  a  b  c
0  1  2  3  4  5
   ^        ^
   |        |
   j        i
a  b  c  a  b  c
0  1  2  3  4  5
      ^        ^
      |        |
      j        i
我们尝试将
添加到唯一的集合,它是重复的。从唯一子字符串的开头,尝试查找
b
。幸运的是,这是在
1
,我们不需要从unique中删除任何内容

a  b  c  a  b  c
0  1  2  3  4  5
   ^        ^
   |        |
   j        i
a  b  c  a  b  c
0  1  2  3  4  5
      ^        ^
      |        |
      j        i
我们试图将添加到唯一的集合,它是重复的。从唯一子字符串的开头,尝试查找
c
。幸运的是,这是在
1
,我们不需要从unique中删除任何内容

a  b  c  a  b  c
0  1  2  3  4  5
   ^        ^
   |        |
   j        i
a  b  c  a  b  c
0  1  2  3  4  5
      ^        ^
      |        |
      j        i

我们完成了。最长的唯一子串是
3

这里是一个具有时间复杂性的解决方案
O(n)
。由于两个原因,它可能比其他解决方案更快

  • 它仅在链断开或到达
    字符串
    末尾时,将不同连续字符链的长度与当前最大值进行比较

  • 通过跟踪每个字符的最后一个索引,而不是 对于子字符串中的字符集,没有任何理由 删除任何元素。当然,这意味着如果
    字符串
    有许多不同的字符,它会占用大量内存

    public static int subStringLength(final String s) {
        final Map<Character, Integer> indices = new HashMap<>();
        int max = 0;
        int start = 0;
        final int length = s.length();
        for (int i = 0; i < length; i++) {
            Integer k = indices.put(s.charAt(i), i);
            if (k != null && k >= start) {
                max = Math.max(max, i - start);
                start = k + 1;
            }
        }
        return Math.max(max, length - start);
    }
    
    public static int subStringLength(最终字符串s){
    最终映射索引=新的HashMap();
    int max=0;
    int start=0;
    最终整数长度=s.长度();
    for(int i=0;i=start){
    max=Math.max(max,i-start);
    开始=k+1;
    }
    }
    返回Math.max(max,length-start);
    }
    

  • 你到底想计算什么?您代码中的一些注释可能会有所帮助,并且标题有误。如果您不对代码进行注释或描述输入和输出,您希望我们如何确定此代码应该做什么。我想我们可能会猜到,但这远远不够。为什么最长的不可重复
    字符串是
    3
    ?这里的逻辑是什么?还不清楚。最大的不可重复字符串始终是完整字符串。但这一切与超出时间限制有什么关系?时间限制是多少?你可以修改hasNoDupeChars的代码,一旦发现重复的代码,就返回。你也应该重用
    集合
    @boristesspider,在
    fail fast
    旁边,我在建议的解决方案中没有做任何其他更改。当人们滥用Knuth引用时,这是我最讨厌的事情之一。这不是Knuth的意思。懒惰的编码从来没有借口。至少在再次使用它之前阅读。@Boristeider