最长的子字符串,不重复字符边缘情况

时间:2017-07-30 18:47:13

标签: string algorithm

我试图解决这个问题:没有重复字符的最长子字符串。问题是,它在几个测试用例中失败了,我不知道如何修复它。我需要你的帮助才能看到我出错的地方。

问题:

  

给定一个字符串,找到没有的最长子字符串的长度   重复人物。

     

示例:

     

鉴于" abcabcbb",答案是" abc",长度为3。

     

鉴于" bbbbb",答案为" b",长度为1。

     

鉴于" pwwkew",答案是" wke",长度为3.注意   答案必须是子串," pwke"是一个子序列,而不是一个   串。

这是我的代码:

function longestSubString(arr){
    let localSum=0,globalSum=0;

    let set = new Set();

    for(let i=0; i<arr.length; i++){
        let current = arr[i];

        //if the key is present in the store.
        if(set.has(current)){
            set.clear();
            localSum = 1;
            set.add(current);
        } else {
            localSum +=1;
            set.add(current);
        }

        if(globalSum < localSum){
            globalSum = localSum;
        }

    }

    return globalSum;
}

试验:

let test = "abcabc"; //returns 3 - correct
let test2 = "bbb"; //returns 1 - correct


let test5 = "dvdf"; //returns 2 - INCORRECT! it should return 3 (i.e for vdf) since I'm doing set.clear() I'm not able to store previous elements.

longestSubString(test5); //incorrect

活:

https://repl.it/Jo5Z/10

5 个答案:

答案 0 :(得分:1)

未经过全面测试!

C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt\corecrt.h(10): fatal error C1083: Cannot open include
file: 'vcruntime.h': No such file or directory (compiling source file ..\..\src\libsass\src\check_nesting.cpp) [C:\Deve
lopment\xxx\xxx\node_modules\gulp-sass\node_modules\node-sass\build\src\libsass.vcxproj]

这个想法是,当你得到重复时,你应该在第一个重复的角色之后从charachter开始,在你的情况function longestSubString(arr){ let localSum=0,globalSum=0; let set = new Set(); for(let i=0; i<arr.length; i++){ let current = arr[i]; //if the key is present in the store. if(set.has(current)){ let a = Array.from(set); a.splice(0,a.indexOf(current)+1); set = new Set(a); set.add(current); localSum = set.size; } else { localSum +=1; set.add(current); } if(globalSum < localSum){ globalSum = localSum; } } return globalSum; } ,当你到达第二个dvdf时,你应该从{{1}继续不是来自d

答案 1 :(得分:1)

您必须考虑子字符串可能从字符串中的任何字符开始。只有在找到重复项时才擦除集合,这样才能只考虑从等于第一个字符的字符开始的子字符串。

O(logn * n ^ 2)解决方案稍微修改一下:

function longestSubString(arr){
    let globalSum=0;

    for(let i=0; i<arr.length; i++){
        let set = new Set();
        let localSum=0;
        for(let j=i; j<arr.lenght; j++){         

            let current = arr[j];

            //if the key is present in the store.
            if(set.has(current)){
                break;
            } else {
                localSum +=1;
                set.add(current);
            }
        }
        if(globalSum < localSum){
            globalSum = localSum;
        }
    }

    return globalSum;
}

还有一个O(n + d)(几乎是线性的)解,d是字母表中的字符数。请参阅http://www.geeksforgeeks.org/length-of-the-longest-substring-without-repeating-characters/

答案 2 :(得分:1)

这里似乎有很多很长的答案。由于两个观察结果,我想到的实现被简化了:

  • 每当遇到重复的字符时,您需要在上一个当前字符出现之后启动下一个子字符串。
  • Set()在迭代时按插入顺序创建一个数组。

function longestSubstring(str) {
  let maxLength = 0
  let current = new Set()

  for (const character of str) {
    if (current.has(character)) {
      const substr = Array.from(current)

      maxLength = Math.max(maxLength, substr.length)
      current = new Set(substr.slice(substr.indexOf(character) + 1))
    }

    current.add(character)
  }

  return Math.max(maxLength, current.size)
}

const tests = [
  "abcabc",
  "bbb",
  "pwwkew",
  "geeksforgeeks",
  "dvdf"
]

tests.map(longestSubstring).forEach(result => console.log(result))

简单的编辑允许我们保留第一次出现的最大子字符串而不是最大长度。

function longestSubstring(str) {
  let maxSubstr = []
  let current = new Set()

  for (const character of str) {
    if (current.has(character)) {
      const substr = Array.from(current)

      maxSubstr = maxSubstr.length < substr.length ? substr: maxSubstr
      current = new Set(substr.slice(substr.indexOf(character) + 1))
    }

    current.add(character)
  }

  const substr = maxSubstr.length < current.size ? Array.from(current) : maxSubstr

  return substr.join('')
}

const tests = [
  "abcabc",
  "bbb",
  "pwwkew",
  "geeksforgeeks",
  "dvdf"
]

tests.map(longestSubstring).forEach(result => console.log(result))

正如我们所看到的,最后一次测试产生了vdf,正如预期的那样。

答案 3 :(得分:0)

下面的解决方案获取O(n+d)时间的长度,并打印最长的非重复字符子串:

public void longestNonRepeatingLength(String a){
        a="dvdf";
        int visitedIndex[] = new int[256];
    int curr_len = 0, max_len = 0, prev_ind = 0, start = 0, end = 1;
    for(int i =0;i<256;i++)
        visitedIndex[i] = -1;
    visitedIndex[a.charAt(0)] = 0;
    curr_len++;
    int i = 0;
    for( i=1;i<a.length();i++){
        prev_ind = visitedIndex[a.charAt(i)];
        if(prev_ind == -1 || i > prev_ind + curr_len)
            curr_len++;
        else{
            if(curr_len>max_len){
                                start = prev_ind + 1;
                                end = i;
                                max_len = curr_len;
                            }

            curr_len = i - prev_ind;

        }
        visitedIndex[a.charAt(i)] = i;
    }
            if(curr_len>max_len){
                                end = i-1;
                                max_len = curr_len;
                            }
    for( i = start;i<=end;i++)
        System.out.print(a.charAt(i));
    System.out.println("");
    System.out.println("Length = "+max_len);
}

答案 4 :(得分:0)

由于if (Context.Database.Connection.State != ConnectionState.Open) Context.Database.Connection.Open(); Context.SaveChanges(); 包含以索引set结尾的字符串的最大非重复字符集,这意味着当您遇到之前看到的字符时,而不是从空集开始你的代码现在就行了,你应该删除你的集合中的所有字符,直到复制的字符为止。

比如说你的输入是i。当遇到第二个"abXcXdef"时,您想要从您的设置中删除"X""a",留下一组"b"作为最长设置点。添加所有其他字符(因为没有重复),最终最长为5。

这样的事情应该有效:

("c","X")

由于每个字符最多添加一次并且最多删除一次,因此这是一种O(N)算法。