Leetcode #3 Longest Substring Without Repeating Characters

来源:互联网 发布:c语言强制类型转换规则 编辑:程序博客网 时间:2024/06/05 20:15

Source: https://leetcode.com/problems/longest-substring-without-repeating-characters/

3. Longest Substring Without RepeatingCharacters

Given a string, find the lengthof the longest substring without repeating characters.

Examples:

Given "abcabcbb", the answer is "abc",which the length is 3.

Given "bbbbb", the answer is "b",with the length of 1.

Given "pwwkew", the answer is "wke",with the length of 3. Note that the answer must be a substring"pwke" is a subsequence and not a substring.

 

Solution:

我试着用两种方法解决这个问题:

方法一:

       申请一个count数组,长度即原字符串s的长度length。count[i]记录着以第i个字符为首字符的无重复元素最长子字符串的长度。count[i]的计算用到了三层循环:

       第一层:用i作检索,i的范围从0到length-1。初始化count[i]为1,置bool类型变量rpt为0;

              第二层:用j检索原字符串中,第i个字符之后的字符。在第三层循环结束后,如果rpt变为1,则跳出该层循环;否则count[i]++;

                     第三层:用k检索s[i]到s[j-1]中的字符,将其与s[j]比较。如果相等,置rpt为1,跳出该层循环。

       这个方法的时间复杂度为O(n3),这里n即为length。代码如下:

class Solution {public:    int lengthOfLongestSubstring(string s) {        int i,j,k;        int ans=0;        bool rpt;        i=0;        while (s[i]!='\0')            i++;        const int length=i;        int count[length];        for (i=0;i<length;i++)        {            count[i]=1;            rpt=0;            for (j=i+1;j<length;j++)            {                for (k=i;k<=j-1;k++)                {                    if (s[j]==s[k])                    {                        rpt=1;                        break;                    }                }                if (rpt==1)                    break;                else                {                    count[i]++;                }            }            if (count[i]>ans)                ans=count[i];        }        return ans;    }};

方法二:

       方法一在数据规模较大时,会有超时问题,因此在这里考虑时间复杂度更低的做法。假设s[i] s[i+1] s[i+2] … s[j-1]为最长的以s[i]为首的无重复元素的字符串,那么这意味着s[j]必然与这一字符串中某个字符相同。这里引入firstRpt数组,长度为length,firstRpt[i]=j。那么,这一无重复字符的字符串长度为firstRpt[i]-i。只要得到该数组,经过一次循环便能得到最长的无重复字符的字符串的长度。这一部分时间复杂度为O(n)。

       为了得到firstRpt数组,另外引入一个长度相同的数组nextRpt,若nextRpt[i]=j,则s[j]为s[i]在原字符串之后第一个和s[i]相同的字符。从nextRpt数组得到firstRpt数组的方法为,从原字符串的末尾开始向前遍历,如果nextRpt[i]<firstRpt[i+1],意味着s[i]与s[i+1] s[i+2] s[i+3] … s[firstRpt[i+1]-1]中的某一个相同,则firstRpt[i]=nextRpt[i];否则,firstRpt[i]=firstRpt[i+1]。显然,初始条件为firstRpt[length-1]=length。这一部分时间复杂度为O(n)。

       可以使用两层循环得到nextRpt数组:

       第一层:用i作检索,i的范围从0到length-1。

              第二层:用j作检索,j的范围从i+1到length-1。只要s[j]=s[i],则置next[i]=j,并跳出该层循环。

       这一部分时间复杂度为O(n2),因而总的时间复杂度为O(n2)。这种做法代码如下:

class Solution {public:    int lengthOfLongestSubstring(string s) {        int i=0,j;        int ans=0;        while (s[i]!='\0')            i++;        const int length=i;        int nextRpt[length];        int firstRpt[length];                for (i=0;i<length;i++)    {    nextRpt[i]=length;    for (j=i+1;j<length;j++)    {    if (s[j]==s[i])    {    nextRpt[i]=j;    break;    }    }    }        firstRpt[length-1]=length;    for(i=length-2; i>=0; i--)          {              if (nextRpt[i] < firstRpt[i+1])                  firstRpt[i] = nextRpt[i];              else                  firstRpt[i] = firstRpt[i+1];         }                if (length>0)            ans=firstRpt[0]-0;    for (i=1;i<length;i++)        {        j=firstRpt[i]-i;        if (j>ans)        ans=j;    }    return ans;    }};

改进后的方法二:

       方法二是可以通过所有测试样例的,但是这里仍然考虑更优的做法。关键在于,能否更快地得到next数组,将时间复杂度降下来。由于字符串的字符是有限的,规模不算太大,因而可以牺牲一部分空间建得一个表latestIndex,大小为ASCII码表的大小(实际上常常用不到这么多),其存储每一个字符最近出现的位置,即其在字符串中出现的下标。对于未出现过的字符,将其位置置为length。那么,从原字符串最后开始向前遍历,先记nextRpt[i]=latestIndex[s[i]],再更新latestIndex[s[i]]=i,即可在O(n)的时间内,得到nextRpt数组。因此,改进后的方法二的时间复杂度为O(n),同时,由于申请了字符串长度大小的两个数组firstRpt与nextRpt,空间复杂度同为O(n)。这种做法代码如下:

class Solution {public:    int lengthOfLongestSubstring(string s) {        int i=0,j;        int ans=0;        while (s[i]!='\0')            i++;        const int length=i;        int latestIndex[256];        for (i=0;i<256;i++)        {            latestIndex[i]=length;        }        int nextRpt[length];        int firstRpt[length];                for (i=length-1;i>=0;i--)        {            nextRpt[i]=latestIndex[s[i]];            latestIndex[s[i]]=i;        }        firstRpt[length-1]=length;    for(i=length-2; i>=0; i--)          {              if (nextRpt[i] < firstRpt[i+1])                  firstRpt[i] = nextRpt[i];              else                  firstRpt[i] = firstRpt[i+1];         }                if (length>0)            ans=firstRpt[0]-0;    for (i=1;i<length;i++)        {        j=firstRpt[i]-i;        if (j>ans)        ans=j;    }    return ans;    }};
0 0
原创粉丝点击