【问题标题】:Find longest substring without repeating characters查找最长的子字符串而不重复字符
【发布时间】:2023-03-31 17:40:03
【问题描述】:

给定length N 中的string S,找出最长的子串,不重复字符。

示例:

输入:“stackoverflow”

输出:“stackoverfl”

如果有两个这样的候选人,从左边第一个返回。我需要线性时间和恒定空间算法。

【问题讨论】:

  • 您对哪一部分有困难?为什么你不能只使用“蛮力”方法?
  • @Paul:我知道蛮力解决方案,TC:O(n^2)。我需要线性时间算法。
  • 如果你需要 O(n) 那么这应该在问题中说明
  • 我认为你不需要 o(n^2) 来进行暴力破解。
  • @RajendraUppal:我只是猜测,但反对者可能认为这个问题“没有显示出任何研究努力”......这并不是一个完全不合理的评估......

标签: string algorithm


【解决方案1】:
  1. 您将需要一个开始和结束定位器(/指针) 字符串和一个数组,用于存储每个字符的信息: 它至少发生过一次吗?

  2. 从字符串的开头开始,两个定位符都指向 字符串的开头。

  3. 将末端定位器向右移动,直到找到 重复(或到达字符串的末尾)。对于每个已处理的字符,将其存储在数组中。 如果这是最大的子字符串,则停止时存储位置。还要记住重复的字符。

  4. 现在对起始定位器做同样的事情,在处理时 每个字符,从数组中删除其标志。移动定位器直到 您会找到较早出现的重复字符。

  5. 如果您还没有到达字符串的末尾,请返回第 3 步。

总体:O(N)

【讨论】:

  • 这仅适用于 ASCII 字符串。对于 Unicode 字符串,将数组更改为哈希表。
  • @EvgenyKluev 大约有 100 万个 Unicode 字符。这完全可以放入由代码点索引的数组中。
  • 在正确答案为“bcdefahijkl”的“ababcdefahijklab”下,该算法似乎会失败
  • @kasavbere 是对的。一个更简单的反例:abadef。您的算法在应该返回 bdef 时返回 adef。问题是,您不允许子字符串重叠。
  • 我看不出你们有什么问题... 以 abadef 为例:3) ab - 发现重复字符(下一个是 a),停止。 4) 在重复字符b 之后移动起始定位符。 3) 移动末端定位器...badef.
【解决方案2】:
import java.util.HashSet;

public class SubString {
    public static String subString(String input){

        HashSet<Character> set = new HashSet<Character>();

        String longestOverAll = "";
        String longestTillNow = "";

        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);

            if (set.contains(c)) {
                longestTillNow = "";
                set.clear();
            }
            longestTillNow += c;
            set.add(c);
            if (longestTillNow.length() > longestOverAll.length()) {
                longestOverAll = longestTillNow;
            }
        }

        return longestOverAll;
    }

    public static void main(String[] args) {
        String input = "substringfindout";
        System.out.println(subString(input));
    }
}

【讨论】:

  • 这是最好的答案,也是最好的方法。非常感谢您发布此答案。
  • @KaveeshKanwal 我不这么认为.. 这个解决方案只返回一个字符串作为输出。如果有 2 个最大长度的子字符串怎么办?
  • 它不会返回正确的字符串,因为当您找到重复项时,您应该从最后一个重复项的开头开始
  • 错误的解决方案!
  • for 循环内部需要再添加一个条件,并使用 list 来添加多个相同的子字符串。如果(longestTillNow.length()>longestOverAll.length()){longestOverAll=longestTillNow;包含列表.clear(); }else if(longestTillNow.length() ==longestOverAll.length()){ containsLists.add(longestTillNow);包含列表.add(longestOverAll); } 例如:kamineekamineeKamineeabcdefabcd 输出:[ekamin,kamine,eKamin,kamine,efabcd,kamine,kamine]
【解决方案3】:

您保留一个数组,指示某个字符最后出现的位置。为方便起见,所有字符都出现在位置 -1。您在保留窗口的字符串上进行迭代,如果在该窗口中重复了一个字符,则您切断以该字符第一次出现结尾的前缀。在整个过程中,您保持最长的长度。这是一个python实现:

def longest_unique_substr(S):
  # This should be replaced by an array (size = alphabet size).
  last_occurrence = {} 
  longest_len_so_far = 0
  longest_pos_so_far = 0
  curr_starting_pos = 0
  curr_length = 0

  for k, c in enumerate(S):
    l = last_occurrence.get(c, -1)
    # If no repetition within window, no problems.
    if l < curr_starting_pos: 
        curr_length += 1
    else:
        # Check if it is the longest so far
        if curr_length > longest_len_so_far: 
            longest_pos_so_far = curr_starting_pos
            longest_len_so_far = curr_length
        # Cut the prefix that has repetition
        curr_length -= l - curr_starting_pos
        curr_starting_pos = l + 1
    # In any case, update last_occurrence
    last_occurrence[c] = k

  # Maybe the longest substring is a suffix
  if curr_length > longest_len_so_far:
    longest_pos_so_far = curr_starting_pos
    longest_len_so_far = curr_length

  return S[longest_pos_so_far:longest_pos_so_far + longest_len_so_far]

【讨论】:

  • 这本质上与 Karoly 的解决方案非常相似。这样做的好处是每个字符需要一次而不是两次,而他的优点是空间效率略高(他的数组是 0/1,因此可以压缩为位掩码)。
  • 写得很好。感谢您的回答。
【解决方案4】:

已编辑:

以下是 concesus 的实现。在我最初发表之后,我想到了这一点。为不删除原文,现如下:

public static String longestUniqueString(String S) {
    int start = 0, end = 0, length = 0;
    boolean bits[] = new boolean[256];
    int x = 0, y = 0;
    for (; x < S.length() && y < S.length() && length < S.length() - x; x++) {
        bits[S.charAt(x)] = true;
        for (y++; y < S.length() && !bits[S.charAt(y)]; y++) {
            bits[S.charAt(y)] = true;
        }
        if (length < y - x) {
            start = x;
            end = y;
            length = y - x;
        }
        while(y<S.length() && x<y && S.charAt(x) != S.charAt(y))
            bits[S.charAt(x++)]=false;
    }
    return S.substring(start, end);
}//

原帖:

这是我的两分钱。包括测试字符串。 boolean bits[] = new boolean[256] 可能会更大以包含一些更大的字符集。

public static String longestUniqueString(String S) {
    int start=0, end=0, length=0;
    boolean bits[] = new boolean[256];
    int x=0, y=0;
    for(;x<S.length() && y<S.length() && length < S.length()-x;x++) {
        Arrays.fill(bits, false);
        bits[S.charAt(x)]=true;
        for(y=x+1;y<S.length() && !bits[S.charAt(y)];y++) {
            bits[S.charAt(y)]=true;
        }           
        if(length<y-x) {
            start=x;
            end=y;
            length=y-x;
        }
    }
    return S.substring(start,end);
}//

public static void main(String... args) {
    String input[][] = { { "" }, { "a" }, { "ab" }, { "aab" }, { "abb" },
            { "aabc" }, { "abbc" }, { "aabbccdefgbc" },
            { "abcdeafghicabcdefghijklmnop" },
            { "abcdeafghicabcdefghijklmnopqrabcdx" },
            { "zxxaabcdeafghicabcdefghijklmnopqrabcdx" },
            {"aaabcdefgaaa"}};
    for (String[] a : input) {
        System.out.format("%s  *** GIVES ***  {%s}%n", Arrays.toString(a),
                longestUniqueString(a[0]));
    }
}

【讨论】:

    【解决方案5】:

    这是另一种只有 2 个字符串变量的解决方案:

    public static String getLongestNonRepeatingString(String inputStr){
        if(inputStr == null){
            return null;
        }
    
        String maxStr = "";
        String tempStr = "";
        for(int i=0; i < inputStr.length(); i++){
            // 1. if tempStr contains new character, then change tempStr  
            if(tempStr.contains("" + inputStr.charAt(i))){
                tempStr = tempStr.substring(tempStr.lastIndexOf(inputStr.charAt(i)) + 1);
            }
            // 2. add new character
            tempStr = tempStr + inputStr.charAt(i);
            // 3. replace maxStr with tempStr if tempStr is longer
            if(maxStr.length() < tempStr.length()){
                maxStr = tempStr;
            }
        }
    
        return maxStr;
    }
    

    【讨论】:

      【解决方案6】:

      JavaScript 中的算法(包含大量 cmets)..

      /**
       Given a string S find longest substring without repeating characters.
       Example:
      
       Input: "stackoverflow"
       Output: "stackoverfl"
      
       Input: "stackoverflowabcdefghijklmn"
       Output: "owabcdefghijklmn"
       */
      function findLongestNonRepeatingSubStr(input) {
          var chars = input.split('');
          var currChar;
          var str = "";
          var longestStr = "";
          var hash = {};
          for (var i = 0; i < chars.length; i++) {
              currChar = chars[i];
              if (!hash[chars[i]]) { // if hash doesn't have the char,
                  str += currChar; //add it to str
              hash[chars[i]] = {index:i};//store the index of the char
          } else {// if a duplicate char found..
              //store the current longest non-repeating chars. until now
              //In case of equal-length, <= right-most str, < will result in left most str
              if(longestStr.length <= str.length) {
                  longestStr = str;
              }
              //Get the previous duplicate char's index
              var prevDupeIndex = hash[currChar].index;
      
              //Find all the chars AFTER previous duplicate char and current one
              var strFromPrevDupe = input.substring(prevDupeIndex + 1, i);
              //*NEW* longest string will be chars AFTER prevDupe till current char
              str = strFromPrevDupe + currChar;
              //console.log(str);
              //Also, Reset hash to letters AFTER duplicate letter till current char
              hash = {};
              for (var j = prevDupeIndex + 1; j <= i; j++) {
                  hash[input.charAt(j)] = {index:j};
              }
          }
        }
        return longestStr.length > str.length ? longestStr : str;
      }
      
      //console.log("stackoverflow => " + findLongestNonRepeatingSubStr("stackoverflow"));      
      //returns stackoverfl
      
      //console.log("stackoverflowabcdefghijklmn => " + 
      findLongestNonRepeatingSubStr("stackoverflowabcdefghijklmn")); //returns owabcdefghijklmn
      
      //console.log("1230123450101 => " + findLongestNonRepeatingSubStr("1230123450101")); //    
      returns 234501
      

      【讨论】:

        【解决方案7】:

        我们可以一一考虑所有子字符串,并检查每个子字符串是否包含所有唯一字符。 将有 n*(n+1)/2 个子串。 substirng 是否包含所有唯一字符可以通过线性时间检查 从左到右扫描它并保留访问字符的地图。此解决方案的时间复杂度为 O(n^3)。`

        import java.util.ArrayList;
        import java.util.Collections;
        import java.util.HashMap;
        import java.util.LinkedHashSet;
        import java.util.List;
        import java.util.Map;
        import java.util.Set;
        
        
        public class LengthOfLongestSubstringWithOutRepeatingChar {
        	public static void main(String[] args)
        	{
        	String s="stackoverflow";	
        	//allSubString(s);
        	System.out.println("result of find"+find(s));
        	}
        	public static String find(String s)
        	{
        		List<String> allSubsring=allSubString(s);
        		Set<String> main =new LinkedHashSet<String>();
        		for(String temp:allSubsring)
        		{
        			boolean a = false;
        			for(int i=0;i<temp.length();i++)
        			{ 
        				for(int k=temp.length()-1;k>i;k--)
        				{
        					if(temp.charAt(k)==temp.charAt(i))
        						a=true;
        				}
        			}
        			if(!a)
        			{
        				main.add(temp);
        			}
        		}
        		/*for(String x:main)
        		{
        		System.out.println(x);	
        		}*/
        		String res=null;
        		int min=0,max=s.length();
        		for(String temp:main)
        		{
        		if(temp.length()>min&&temp.length()<max)
        		{
        			min=temp.length();
        			res=temp;
        		}
        		}
        		System.out.println(min+"ha ha ha"+res+"he he he");
        		return res;
        		
        	}
        	//substrings left to right ban rahi hai
        
        private static List<String> allSubString(String str) {
        	List<String> all=new ArrayList<String>();
        	int c=0;
        	for (int i = 0; i < str.length(); i++) {
        		for (int j = 0; j <= i; j++) {
        			if (!all.contains(str.substring(j, i + 1)))
        			{
        				c++;
        				all.add(str.substring(j, i + 1));
        			}
        		}
        	}
        	for(String temp:all)
        	{
        		System.out.println("substring :-"+temp);
        	}
        	System.out.println("count"+c);
        	return all;
        }
        }

        【讨论】:

          【解决方案8】:

          另一个 O(n) JavaScript 解决方案。它在循环期间不会改变字符串;它只是跟踪迄今为止最长的子字符串的偏移量和长度:

          function longest(str) {
              var hash = {}, start, end, bestStart, best;
              start = end = bestStart = best = 0;
              while (end < str.length) {
                  while (hash[str[end]]) hash[str[start++]] = 0;
                  hash[str[end]] = 1;
                  if (++end - start > best) bestStart = start, best = end - start;
              }
              return str.substr(bestStart, best);
          }
           
          // I/O for snippet
          document.querySelector('input').addEventListener('input', function () {
              document.querySelector('span').textContent = longest(this.value);
          });
          Enter word:<input><br>
          Longest: <span></span>

          【讨论】:

            【解决方案9】:

            简单的python sn-p l=长度 p=位置 maxl=maxlength maxp=maxposition

            【讨论】:

            • 图像有什么意义????为什么不包含代码....作为文本?
            【解决方案10】:

            经过测试和工作。为了便于理解,我想有一个抽屉可以放字母。

            功能:

            
                public int lengthOfLongestSubstring(String s) {
                    int maxlen = 0;
                    int start = 0;
                    int end = 0;
                    HashSet<Character> drawer = new HashSet<Character>(); 
                    for (int i=0; i<s.length(); i++) {
                        char ch = s.charAt(i);
                        if (drawer.contains(ch)) {
                            //search for ch between start and end
                            while (s.charAt(start)!=ch) {
                                //drop letter from drawer
                                drawer.remove(s.charAt(start));
                                start++;
                            }
                            //Do not remove from drawer actual char (it's the new recently found)
                            start++;
                            end++;
                        }
                        else {
                            drawer.add(ch);
                            end++;
                            int _maxlen = end-start;
                            if (_maxlen>maxlen) {
                                maxlen=_maxlen;
                            }
                        }
                    }
                    return maxlen;
                }
            

            【讨论】:

              【解决方案11】:

              python中不重复字符的最长子串

              public int lengthOfLongestSubstring(String s) {
                  if(s.equals(""))
                      return 0;
                  String[] arr = s.split("");
                  HashMap<String,Integer> map = new HashMap<>();
                  Queue<String> q = new LinkedList<>();
              
                  int l_till = 1;
                  int l_all = 1;
                  map.put(arr[0],0);
                  q.add(arr[0]);
                  for(int i = 1; i < s.length(); i++){
                      if (map.containsKey(arr[i])) {
                          if(l_till > l_all){
                              l_all = l_till;
                          }
                          while(!q.isEmpty() && !q.peek().equals(arr[i])){
                              map.remove(q.remove());
                          }
                          if(!q.isEmpty())
                             map.remove(q.remove());
                          q.add(arr[i]);
                          map.put(arr[i],i);
                          //System.out.println(q);
                          //System.out.println(map);
                          l_till = q.size();
                      }
                      else {
                          l_till = l_till + 1;
                          map.put(arr[i],i);
                          q.add(arr[i]);
                      }
                  }
                  if(l_till > l_all){
                              l_all = l_till;
                          }
                  return l_all;
              }
              

              【讨论】:

                【解决方案12】:

                我在一次采访中被问到同样的问题。

                我编写了 Python3 代码,以查找具有所有不同字符的子字符串的第一次出现。在我的实现中,我从 index = 0 开始并遍历输入字符串。迭代时使用 Python dict seems 将输入字符串中的字符索引存储在迭代中已访问过的字符索引。

                在迭代中,如果 char c,在当前子字符串中找不到 – 引发 KeyError 异常

                如果发现c 是当前子字符串中的重复字符(因为c 之前在迭代过程中出现 - 命名该索引last_seen)开始一个新的子字符串

                def lds(string: str) -> str:
                    """ returns first longest distinct substring in input `string` """
                    seens = {}
                    start, end, curt_start = 0, 0, 0
                    for curt_end, c in enumerate(string):
                        try:
                            last_seen = seens[c]
                            if last_seen < curt_start:
                                raise KeyError(f"{c!r} not found in {string[curt_start: curt_end]!r}")
                            if end - start <  curt_end - curt_start:
                                start, end = curt_start, curt_end
                            curt_start = last_seen + 1
                        except KeyError:
                            pass
                        seens[c] = curt_end
                    else: 
                        # case when the longest substring is suffix of the string, here curt_end
                        # do not point to a repeating char hance included in the substring
                        if string and end - start <  curt_end - curt_start + 1:
                            start, end = curt_start, curt_end + 1
                    return string[start: end]
                

                【讨论】:

                  【解决方案13】:
                  private static string LongestSubstring(string word)
                          {
                              var set = new HashSet<char>();
                              string longestOverAll = "";
                              string longestTillNow = "";
                  
                              foreach (char c in word)
                              {
                                  if (!set.Contains(c))
                                  {
                                      longestTillNow += c;
                                      set.Add(c);
                                  }
                                  else
                                  {
                                      longestTillNow = string.Empty;
                                  }
                  
                                  if (longestTillNow.Length > longestOverAll.Length)
                                  {
                                      longestOverAll = longestTillNow;
                                  }
                              }
                  
                              return longestOverAll;
                          }
                  

                  【讨论】:

                    【解决方案14】:
                    import java.util.ArrayList;
                    import java.util.HashSet;
                    import java.util.LinkedHashSet;
                    import java.util.List;
                    import java.util.Set;
                    import java.util.TreeMap;
                    
                    public class LongestSubString2 {
                    
                        public static void main(String[] args) {
                            String input = "stackoverflowabcdefghijklmn";
                            List<String> allOutPuts = new ArrayList<String>();
                            TreeMap<Integer, Set> map = new TreeMap<Integer, Set>();
                            for (int k = 0; k < input.length(); k++) {
                                String input1 = input.substring(k);
                                String longestSubString = getLongestSubString(input1);
                                allOutPuts.add(longestSubString);
                            }
                    
                            for (String str : allOutPuts) {
                                int strLen = str.length();
                                if (map.containsKey(strLen)) {
                                    Set set2 = (HashSet) map.get(strLen);
                                    set2.add(str);
                                    map.put(strLen, set2);
                                } else {
                                    Set set1 = new HashSet();
                                    set1.add(str);
                                    map.put(strLen, set1);
                                }
                    
                            }
                            System.out.println(map.lastKey());
                            System.out.println(map.get(map.lastKey()));
                        }
                    
                        private static void printArray(Object[] currentObjArr) {
                            for (Object obj : currentObjArr) {
                                char str = (char) obj;
                                System.out.println(str);
                            }
                    
                        }
                    
                        private static String getLongestSubString(String input) {
                    
                            Set<Character> set = new LinkedHashSet<Character>();
                            String longestString = "";
                            int len = input.length();
                            for (int i = 0; i < len; i++) {
                                char currentChar = input.charAt(i);
                                boolean isCharAdded = set.add(currentChar);
                                if (isCharAdded) {
                                    if (i == len - 1) {
                                        String currentStr = getStringFromSet(set);
                    
                                        if (currentStr.length() > longestString.length()) {
                                            longestString = currentStr;
                                        }
                                    }
                                    continue;
                                } else {
                                    String currentStr = getStringFromSet(set);
                    
                                    if (currentStr.length() > longestString.length()) {
                                        longestString = currentStr;
                                    }
                                    set = new LinkedHashSet<Character>(input.charAt(i));
                                }
                    
                            }
                    
                            return longestString;
                        }
                    
                        private static String getStringFromSet(Set<Character> set) {
                    
                            Object[] charArr = set.toArray();
                    
                            StringBuffer strBuff = new StringBuffer();
                            for (Object obj : charArr) {
                                strBuff.append(obj);
                    
                            }
                    
                            return strBuff.toString();
                        }
                    }
                    

                    【讨论】:

                    • 在代码中加个解释也无妨。
                    【解决方案15】:

                    这是我的解决方案,它被 leetcode 接受了。然而,在我看到统计数据后,我看到很多解决方案的结果要快得多....意思是,我的解决方案对于所有测试用例都在 600 毫秒左右,而大多数 js 解决方案在 200 -300 毫秒括号左右.. 谁能告诉我为什么我的解决方案很慢吗??

                    var lengthOfLongestSubstring = function(s) {
                      var arr = s.split("");
                    
                      if (s.length === 0 || s.length === 1) {
                        return s.length;
                      }
                    
                      var head = 0,
                        tail = 1;
                      var str = arr[head];
                      var maxL = 0;
                      while (tail < arr.length) {
                        if (str.indexOf(arr[tail]) == -1) {
                          str += arr[tail];
                          maxL = Math.max(maxL, str.length);
                          tail++;
                        } else {
                          maxL = Math.max(maxL, str.length);
                          head = head + str.indexOf(arr[tail]) + 1;
                          str = arr[head];
                          tail = head + 1;
                        }
                      }
                      return maxL;
                    };

                    【讨论】:

                      【解决方案16】:

                      我在 python 中发布 O(n^2) 。我只是想知道 Karoly Horvath 提到的技术是否有任何类似于现有搜索/排序算法的步骤?

                      我的代码:

                      def main():
                          test='stackoverflow'
                          tempstr=''
                          maxlen,index=0,0
                          indexsubstring=''
                          print 'Original string is =%s\n\n' %test
                      
                          while(index!=len(test)):
                              for char in test[index:]:
                                  if char not in tempstr:
                                      tempstr+=char
                                      if len(tempstr)> len(indexsubstring):
                                         indexsubstring=tempstr
                                  elif (len(tempstr)>=maxlen):
                                         maxlen=len(tempstr)
                                         indexsubstring=tempstr
                                         break
                              tempstr=''
                              print 'max substring length till iteration with starting index =%s is %s'%(test[index],indexsubstring)
                              index+=1
                      
                      if __name__=='__main__':
                          main()
                      

                      【讨论】:

                        【解决方案17】:

                        简单易行

                        import java.util.Scanner;
                        
                        public class longestsub {
                        
                            static Scanner sn = new Scanner(System.in);
                            static String word = sn.nextLine();
                        
                            public static void main(String[] args) {
                                System.out.println("The Length is " +check(word));
                            }
                            private static int check(String word) {
                                String store="";
                                for (int i = 0; i < word.length(); i++) {
                                    if (store.indexOf(word.charAt(i))<0) {
                                        store = store+word.charAt(i);
                                    }
                                }
                                System.out.println("Result word " +store);
                                return store.length();
                            }
                        
                        }
                        

                        【讨论】:

                          【解决方案18】:

                          在 Python 中没有完全优化但简单的答案

                          def lengthOfLongestSubstring(s):
                                temp,maxlen,newstart = {},0,0
                                for i,x in enumerate(s):
                                      if x in temp:
                                            newstart = max(newstart,s[:i].rfind(x)+1)
                                      else:
                                            temp[x] = 1
                                      maxlen = max(maxlen, len(s[newstart:i + 1]))
                                return maxlen
                          

                          我认为代价高昂的事情是rfind,这就是它没有完全优化的原因。

                          【讨论】:

                            【解决方案19】:

                            这是我的解决方案。希望对您有所帮助。

                              function longestSubstringWithoutDuplication(str) {
                                  var max = 0;
                            
                                  //if empty string
                                  if (str.length === 0){
                                    return 0;
                                  } else if (str.length === 1){ //case if the string's length is 1
                                    return 1;
                                  }
                            
                                  //loop over all the chars in the strings
                                  var currentChar,
                                      map = {},
                                      counter = 0; //count the number of char in each substring without duplications
                                  for (var i=0; i< str.length ; i++){
                                    currentChar = str.charAt(i);
                            
                                    //if the current char is not in the map
                                    if (map[currentChar]  == undefined){
                                      //push the currentChar to the map
                                          map[currentChar] = i;
                                          if (Object.keys(map).length > max){
                                             max = Object.keys(map).length;
                                          }
                                    } else { //there is duplacation
                                      //update the max
                                      if (Object.keys(map).length > max){
                                        max = Object.keys(map).length;
                                      }
                                      counter = 0; //initilize the counter to count next substring
                                      i = map[currentChar]; //start from the duplicated char
                                      map = {}; // clean the map
                                    }
                                  }
                            
                            
                                 return max;
                                }
                            

                            【讨论】:

                            • 想详细说明这如何解决 OP 的问题?
                            【解决方案20】:

                            这是我的 javascript 和 cpp 实现的详细信息:https://algorithm.pingzhang.io/String/longest_substring_without_repeating_characters.html

                            我们想找到最长的子串,而不是重复的字符。我想到的第一件事是我们需要一个哈希表来存储子字符串中的每个字符,这样当一个新字符进来时,我们可以很容易地知道这个字符是否已经在子字符串中。我称之为valueIdxHash。然后,一个子字符串有一个startIdx 和endIdx。所以我们需要一个变量来跟踪子字符串的起始索引,我称之为startIdx。假设我们在索引i,并且我们已经有一个子字符串(startIdx, i - 1)。现在,我们要检查这个子字符串是否可以继续增长。

                            如果valueIdxHash 包含 str[i],则表示它是重复字符。但是我们仍然需要检查这个重复的字符是否在子字符串(startIdx, i - 1)中。所以我们需要检索上次出现的str[i]的索引,然后将该索引与startIdx进行比较。

                            • 如果startIdx较大,则表示最后出现的str[i]在子字符串之外。因此子串可以继续增长。
                            • 如果startIdx 较小,则表示最后出现的str[i] 在子字符串内。因此,子串不能再增长。 startIdx 将更新为 valueIdxHash[str[i]] + 1 并且新的子字符串 (valueIdxHash[str[i]] + 1, i) 有可能继续增长。

                            如果valueIdxHash 不包含 str[i],则子串可以继续增长。

                            【讨论】:

                              【解决方案21】:

                              我修改了我的解决方案以“查找最长子字符串的长度而不重复字符”。

                                      public string LengthOfLongestSubstring(string s) {
                                  var res = 0;
                                  var dict = new Dictionary<char, int>();
                                  var start = 0;
                              
                                  for(int i =0; i< s.Length; i++)
                                  {
                                      if(dict.ContainsKey(s[i]))
                                      {
                                          start = Math.Max(start, dict[s[i]] + 1); //update start index
                                          dict[s[i]] = i;
                                      }
                                      else
                                      {
                                          dict.Add(s[i], i);
                                      }
                              
                                      res = Math.Max(res, i - start + 1);  //track max length
                                  }
                                  return s.Substring(start,res);
                              }
                              

                              【讨论】:

                                【解决方案22】:
                                import java.util.HashMap;
                                import java.util.HashSet;
                                
                                public class SubString {
                                    public static String subString(String input) {
                                
                                        String longesTillNOw = "";
                                
                                        String longestOverAll = "";
                                        HashMap<Character,Integer> chars = new HashMap<>();
                                        char[] array=input.toCharArray();
                                        int start=0;
                                        for (int i = 0; i < array.length; i++) {
                                            char charactor = array[i];
                                            if (chars.containsKey(charactor) ) {
                                                start=chars.get(charactor)+1;
                                                i=start;
                                                chars.clear();
                                                longesTillNOw = "";
                                            } else {
                                                chars.put(charactor,i);
                                                longesTillNOw = longesTillNOw + charactor;
                                                if (longesTillNOw.length() > longestOverAll.length()) {
                                                    longestOverAll = longesTillNOw;
                                                }
                                            }
                                        }
                                        return longestOverAll;
                                
                                    }
                                
                                    public static void main(String[] args) {
                                        String input = "stackoverflowabcdefghijklmn";
                                        System.out.println(subString(input));
                                    }
                                }
                                

                                【讨论】:

                                  【解决方案23】:

                                  这里有两种方法可以在 JavaScript 中解决这个问题。

                                  蛮力 方法是遍历字符串两次,检查每个子字符串与其他所有子字符串,并找到子字符串唯一的最大长度。我们需要两个函数:一个检查子字符串是否唯一,第二个函数执行我们的双循环。

                                  // O(n) time
                                  const allUnique = str => {
                                    const set = [...new Set(str)];
                                    return (set.length == str.length) ? true: false;
                                  }
                                  
                                  // O(n^3) time, O(k) size where k is the size of the set
                                  const lengthOfLongestSubstring = str => {
                                    let result = 0,
                                        maxResult = 0;
                                    for (let i=0; i<str.length-1; i++) {
                                      for (let j=i+1; j<str.length; j++) {
                                        if (allUnique(str.substring(i, j))) {
                                          result = str.substring(i, j).length;
                                          if (result > maxResult) {
                                            maxResult = result;
                                          }
                                        }
                                      }
                                    return maxResult;
                                    }
                                  }
                                  

                                  这具有O(n^3) 的时间复杂度,因为我们执行一个双循环O(n^2),然后在O(n) 之上为我们的独特功能执行另一个循环。空间是我们集合的大小,可以泛化为O(n) 或更准确地说是O(k),其中k 是集合的大小。

                                  贪婪方法是只循环一次,并在我们进行时跟踪最大唯一子串长度。我们可以使用数组或哈希映射,但我认为新的.includes() 数组方法很酷,所以让我们使用它。

                                  const lengthOfLongestSubstring = str => {
                                    let result = [],
                                        maxResult = 0;
                                  
                                    for (let i=0; i<str.length; i++) {
                                      if (!result.includes(str[i])) {
                                        result.push(str[i]);
                                      } else {
                                        maxResult = i;
                                      }
                                    }
                                  
                                    return maxResult;
                                  }
                                  

                                  这具有O(n) 的时间复杂度和O(1) 的空间复杂度。

                                  【讨论】:

                                    【解决方案24】:

                                    这个问题可以在 O(n) 时间复杂度内解决。 初始化三个变量

                                    1. 开始(索引指向非重复子串的开始,初始化为0)。
                                    2. End(索引指向非重复子串的结尾,初始化为0)
                                    3. Hasmap(包含上次访问的字符索引位置的对象。例如:{'a':0, 'b':1} for string "ab")

                                    步骤: 遍历字符串并执行以下操作。

                                    1. 如果当前字符不在 hashmap() 中,则将其添加为 hashmap,字符为键,其索引为值。
                                    2. 如果当前字符存在于 hashmap 中,则

                                      a) 检查起始索引是否小于或等于哈希图中针对字符的值(之前访问过的相同字符的最后索引),

                                      b) 然后将起始变量值分配为哈希图的值 + 1(之前访问过的相同字符的最后索引 + 1);

                                      c) 通过覆盖 hashmap 的当前字符值作为当前字符索引来更新 hashmap。

                                      d) 将 end-start 计算为最长的子字符串值,如果它大于之前最长的非重复子字符串,则更新。

                                    以下是针对此问题的 Javascript 解决方案。

                                    var lengthOfLongestSubstring = function(s) {
                                        let length = s.length;
                                        let ans = 0;
                                        let start = 0,
                                            end = 0;
                                        let hashMap = {};
                                    
                                        for (var i = 0; i < length; i++) {
                                    
                                            if (!hashMap.hasOwnProperty(s[i])) {
                                                hashMap[s[i]] = i;
                                            } else {
                                                if (start <= hashMap[s[i]]) {
                                                    start = hashMap[s[i]] + 1;
                                                }
                                                hashMap[s[i]] = i;
                                            }
                                            end++;
                                            ans = ans > (end - start) ? ans : (end - start);
                                        }
                                        return ans;
                                    };
                                    

                                    【讨论】:

                                      【解决方案25】:

                                      问题:找到最长的不重复字符的子串。 示例 1:

                                          import java.util.LinkedHashMap;
                                          import java.util.Map;
                                      
                                          public class example1 {
                                      
                                              public static void main(String[] args) {
                                                  String a = "abcabcbb";
                                                     // output => 3
                                                  System.out.println( lengthOfLongestSubstring(a));
                                      
                                              }
                                      
                                              private static int lengthOfLongestSubstring(String a) {
                                                     if(a == null  || a.length() == 0) {return  0 ;}  
                                                     int res = 0 ;
                                                  Map<Character , Integer> map = new LinkedHashMap<>();
                                                    for (int i = 0; i < a.length(); i++) {
                                                        char ch = a.charAt(i);
                                                      if (!map.containsKey(ch)) {
                                             //If ch is not present in map, adding ch into map along with its position
                                                          map.put(ch, i);
                                      
                                                      }else {
                                      /*
                                      If char ch is present in Map, reposition the cursor i to the position of ch and clear the Map.
                                      */ 
                                                          i = map.put(ch, i);// updation of index
                                                           map.clear();
                                                      }//else
                                      
                                                      res = Math.max(res, map.size());
                                      
                                                  }
                                      
                                      
                                      
                                                  return res;
                                              }
                                      
                                          }
                                      

                                      如果您想要没有重复字符的最长字符串作为输出,请在 for 循环中执行此操作:

                                      String res ="";// global
                                          int len = 0 ;//global
                                       if(len < map.size()) {
                                           len = map.size();
                                          res = map.keySet().toString();
                                       }
                                      System.out.println("len -> " + len);
                                      System.out.println("res => " + res);
                                      

                                      【讨论】:

                                      • 感谢您提供此代码 sn-p,它可能会提供一些有限的短期帮助。一个正确的解释would greatly improve 其长期价值,通过展示为什么这是解决问题的好方法,并将使其对未来有其他类似问题的读者更有用。请edit您的回答添加一些解释,包括您所做的假设。
                                      【解决方案26】:
                                      def max_substring(string):
                                         last_substring = ''
                                         max_substring  = ''
                                         for x in string:
                                             k = find_index(x,last_substring)
                                             last_substring = last_substring[(k+1):]+x
                                             if len(last_substring) > len(max_substring):
                                                     max_substring  = last_substring        
                                         return max_substring
                                      
                                      def find_index(x, lst):
                                         k = 0
                                         while k <len(lst):
                                            if lst[k] == x:
                                               return k
                                            k +=1
                                         return -1
                                      

                                      【讨论】:

                                        【解决方案27】:

                                        我们可以使用这样的东西吗?

                                        def longestpalindrome(str1):
                                            arr1=list(str1)
                                            s=set(arr1)
                                            arr2=list(s)
                                            return len(arr2)
                                        
                                        
                                        
                                        str1='abadef'
                                        a=longestpalindrome(str1)
                                        print(a)
                                        

                                        如果只返回子字符串的长度

                                        【讨论】:

                                          【解决方案28】:

                                          算法:
                                          1) 初始化一个空字典dct来检查字符串中是否已经存在任何字符。
                                          2) cnt - 保持子串的计数而不重复字符。
                                          3)l 和 r 是初始化到字符串第一个索引的两个指针。
                                          4) 循环遍历字符串的每个字符。
                                          5) 如果 dct 中不存在该字符,则添加它并增加 cnt。
                                          6) 如果它已经存在,则检查 cnt 是否大于 resStrLen。
                                          7) 从 dct 中删除字符并将左指针移动 1 并减少计数。
                                          8) 重复 5,6,7 直到 l,r 大于或等于输入字符串的长度。
                                          9) 最后再做一次检查,以处理输入字符串不重复字符等情况。

                                          这是一个简单的 python 程序,用于查找最长的子字符串而不重复字符


                                          a="stackoverflow"
                                          strLength = len(a)
                                          dct={}
                                          resStrLen=0
                                          cnt=0
                                          l=0
                                          r=0
                                          strb=l
                                          stre=l
                                          while(l<strLength and r<strLength):
                                              if a[l] in dct:
                                                  if cnt>resStrLen:
                                                      resStrLen=cnt
                                                      strb=r
                                                      stre=l
                                                  dct.pop(a[r])
                                                  cnt=cnt-1
                                                  r+=1    
                                              else:
                                                  cnt+=1
                                                  dct[a[l]]=1
                                                  l+=1
                                          
                                          if cnt>resStrLen:
                                              resStrLen=cnt
                                              strb=r
                                              stre=l
                                          
                                          print "Result String Length : "+str(resStrLen)
                                          print "Result String : " + a[strb:stre]
                                          



                                          【讨论】:

                                            【解决方案29】:

                                            C 中的解决方案。

                                            #include<stdio.h>
                                            #include <string.h>
                                            
                                            void longstr(char* a, int *start, int *last)
                                            {
                                                *start = *last = 0;
                                                int visited[256];
                                                for (int i = 0; i < 256; i++)
                                                {
                                                    visited[i] = -1;
                                                }
                                                int max_len = 0;
                                                int cur_len = 0;
                                                int prev_index;
                                                visited[a[0]] = 0;
                                                for (int i = 1; i < strlen(a); i++)
                                                {
                                                    prev_index = visited[a[i]];
                                                    if (prev_index == -1 || i - cur_len > prev_index)
                                                    {
                                                        cur_len++;
                                                        *last = i;
                                                    }
                                                    else
                                                    {
                                                        if (max_len < cur_len)
                                                        {
                                                            *start = *last - cur_len;
                                                            max_len = cur_len;
                                                        }
                                                        cur_len = i - prev_index;
                                                    }
                                                    visited[a[i]] = i;
                                                }
                                                if (max_len < cur_len)
                                                {
                                                    *start = *last - cur_len;
                                                    max_len = cur_len;
                                                }
                                            }
                                            
                                            int main()
                                            {
                                                char str[] = "ABDEFGABEF";
                                                printf("The input string is %s \n", str);
                                                int start, last;
                                                longstr(str, &start, &last);
                                                //printf("\n %d  %d \n", start, last);
                                                memmove(str, (str + start), last - start);
                                                str[last] = '\0';
                                                printf("the longest non-repeating character substring is %s", str);
                                                return 0;
                                            }
                                            

                                            【讨论】:

                                              【解决方案30】:
                                              public int lengthOfLongestSubstring(String s) {
                                                  int startIndex = 0;
                                                  int maxLength = 0;
                                                  //since we have 256 ascii chars
                                                  int[] lst = new int[256];
                                                  Arrays.fill(lst,-1);
                                                  for (int i = 0; i < s.length(); i++) {
                                                      char c = s.charAt(i);
                                                      //to get ascii value of c
                                                      int ic = (int) c;
                                                      int value = lst[ic];
                                                      //this will say to move start index to next index of the repeating char
                                                      //we only do this if the repeating char index is greater than start index
                                                      if (value >= startIndex) {
                                                          maxLength = Math.max(maxLength, i - startIndex);
                                                          startIndex = value + 1;
                                                      }
                                                      lst[ic] = i;
                                                  }
                                                  //when we came to an end of string
                                                  return Math.max(maxLength,s.length()-startIndex);
                                              }
                                              

                                              这是最快的,它是线性时间和恒定空间

                                              【讨论】:

                                                猜你喜欢
                                                • 1970-01-01
                                                • 2016-08-11
                                                • 2018-10-18
                                                • 1970-01-01
                                                • 1970-01-01
                                                • 2020-07-04
                                                • 2020-12-09
                                                • 2019-09-11
                                                相关资源
                                                最近更新 更多