Given a string, find the length of the longest substring without repeating characters. For example, the longest substring without repeating letters for "abcabcbb" is "abc", which the length is 3. For "bbbbb" the longest substring is "b", with the length of 1.
解法一:枚举出字符串的所有子串,去掉有重复字符的那部分,最后找出其中长度最长的那个。最笨的办法,时间复杂度O(n^4)。
int max_unique_substring1(char * str) { int maxlen = 0; int begin = 0; int n = strlen(str); for(int i=0; i<n; ++i) for(int j=1; j<n; ++j) { int flag = 0; for(int m=i; m<=j; ++m) { for(int n=m+1; n<j; ++n) { if(str[n] == str[m]) { flag = 1; break; } } if(flag == 1) break; } if(flag==0 && j-i+1>maxlen) { maxlen = j-i+1; begin = i; } } printf("%.*s ", maxlen, &str[begin]); return maxlen; }
解法二:对解法一的检验子串是否“无重复字符”进行改进,使用hash表记录字符是否出现过,时间复杂度减小为O(n^2)。
int max_unique_substring2(char * str) { int i,j; int begin; int maxlen = 0; int hash[256]; int n = strlen(str); for(i=0; i<n; ++i) { memset(hash,0,sizeof(hash)); hash[str[i]] = 1; for(j=i+1; j<n; ++j) { if(hash[str[j]] == 0) hash[str[j]] = 1; else break; } if(j-i > maxlen) { maxlen = j-i; begin = i; } } printf("%.*s ", maxlen, &str[begin]); return maxlen; }
解法三:对于字符串"axbdebpqawuva",构造下表:
表中,字符串有3个‘a’,有2个‘b’,其余为单一字符。next[]记录了下一个与之重复的字符的位置,如str[0]=str[8]=str[12]=‘a’,这时next[0]=8,next[8]=12,next[12]=13,其余同理。值得注意的是,对于没有重复字符的,next[]存储字符结束符‘ ’的下标,即13。
这里,first[i]表示i之后,第一次出现重复字符的那个位置。例如,str[0]之后,第一次出现的重复字符是str[5]=‘b’,当然,从str[1],str[2]开始也是一样。而从str[3]开始,要到str[12]才出现重复字符‘a’。可以证明,从str[i]起的最长符合要求的长度为first[i]-i,区间为[i,first[i]-1]由此得解。上述最长串是当i=3时,first[i]-i=12-3=9。结果串为debpqawuv。
//O(N)的时间复杂度 int max_unique_substring3(char * str) { int maxlen = 0; int begin = 0; int n = strlen(str); int * next = (int*)malloc(sizeof(int)*n); //next[i]记录了下一个与str[i]重复的字符的位置 int * first = (int*)malloc(sizeof(int)*(n+1)); //first[i]记录str[i]后面最近的一个重复点 int hash[256]; memset(hash,n,sizeof(hash)); first[n] = n; for(int i=n-1; i>=0; i--) { next[i] = hash[str[i]]; hash[str[i]] = i; if (next[i] < first[i+1]) first[i] = next[i]; else first[i] = first[i+1]; //生成first[]表,复杂度是O(N)的 } for(int i=0; i<n; i++) { if (first[i]-i > maxlen) { maxlen = first[i]-i; begin = i; } } free(first); free(next); printf("%.*s ", maxlen, &str[begin]); return maxlen; }
解法四:使用后缀数组
对这个字符串构造后缀数组,在每个后缀数组中,寻找没有重复字符的最长前缀,最长的前缀就是要找的子串。
//得到字符串最长的无重复的前缀长度 int longestlen(char * p) { int hash[256]; int len = 0; memset(hash,0,sizeof(hash)); while (*p && !hash[*p]) { hash[*p] = 1; ++ len; ++ p; } return len; } //使用后缀数组解法 int max_unique_substring4(char * str) { int maxlen = -1; int begin = 0; char *a[99999]; int n = 0; while(*str != '