zoukankan      html  css  js  c++  java
  • 最长不重复子串

    1.穷举法,每往后查找一个字符,将其与前面的串比较一遍,不重复将其加到前面的串里,否则从前面串的下一个字符再次进行同样的循环。(这里当该字符与前面串第一个重复时才不浪费时间,否者会多进行很多次无用的比较)

    void GEtDIfNUm1(char* str)
    {
        int maxlen=0;
        int begin=0;
        int len=strlen(str);
        int flag;
        if(len==1)   //防止一个字符那种情况
        {
            cout<<str[0]<<endl;
            return;
        }
        for(int i=0;i<len-1;i++)
        {
            flag=0;
            begin=0;
            for(int j=i+1;j<len;j++)
            {
                for(int m=i;m<j;m++)
                {
                    if(str[m]==str[j])
                    {
                        if(j-i>maxlen)
                        {
                            maxlen=j-i;
                            begin=i;
    
                        }
                        flag=1;
                        break;
                    }
                }
                if(flag==1)
                   break;
            }
        }
        for(int i=begin;i<maxlen;i++)
          cout<<str[i];
        cout<<maxlen<<endl;
    }

    时间复杂度:O(n^3)

    2.hash表去记录重复的字符

    int GEtDIfNUm2(char* str)
    {
        int hash[250];
        int len=strlen(str);
        int begin=0;
        int maxNUm=0;
        for(int i=0;i<len-1;i++)
        {
            memset(hash,0,sizeof(hash));
            hash[str[i]]=1;
            for(int j=i+1;j<len;j++)
            {
                if(hash[str[j]]==1)
                {
                    begin=i;
                    if(j-i>maxNUm)
                    {
                       maxNUm=j-i;
                       break;
                    }
                }
            }
        }
        return maxNUm;
    }

    时间复杂度:O(n^2)
    3.hash表加dp

    一.构造first数组和next数组,first数组是指包括当前字符的后面第一次出现重复字符的下标,next数组指和当前字符重复的下一个位置的下标,如果出现同一个字符的多次重复的情况,则每次取它后面距离最近的那个字符的下标。最后就是求所有情况中first[i]-i最大的那个。

    int GEtDIfNUm3(char* str)
    {
        int MAxLEn=0;
        int BEgin=0;
        int n=strlen(str);
        int* first=(int*)malloc(sizeof(int)*(n+1));
        int* next=(int*)malloc(sizeof(int)*n);
        int hash[256];
        first[n]=n;
        memset(hash,n,sizeof(hash));
        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];
            }
        }
        for(int i=0;i<n;i++)
        {
            if(first[i]-i>MAxLEn)
            {
                MAxLEn=first[i]-i;
                BEgin=i;
            }
        }
        for(int i=BEgin;i<BEgin+MAxLEn;i++)
        {
            cout<<str[i];
        }
        cout<<endl;
        return MAxLEn;
    
    
    }

    时间复杂度:O(n)

    二.在上面的一点改进,上面更加像从后往前,这里就从前往后了,visit数组保留的是当前字符的下标,后面出现重复的时就会进行比较,如果该重复的字符在目前比较的字符串中间的话,那么就从下一个字符串开始比较,下一个字符串开始的位置就是该重复字符的下一个字符,如果不在中间,就把该字符加到目前字符串中,并把他的下标改为他目前的位置。

    int GEtDIfNUm4(char* str)
    {
       int visit[256];
       memset(visit,-1,sizeof(visit));
       int n=strlen(str);
       int CUrLEn=1;
       int BEgin;
       int MAxLEn=0;
       int lastBEgin=0;
    
       visit[str[0]]=0;
       for(int i=1;i<n;i++)
       {
           if(visit[str[i]]==-1)
           {
               CUrLEn++;
               visit[str[i]]=i;
           }
           else
           {
               if(lastBEgin<visit[str[i]])    //这里那些没必要进行的比较删除了,上面穷举这里要从头开始,而这里只是从那个重复的字符后面开始
               {
                   CUrLEn=i-visit[str[i]];
                   lastBEgin=visit[str[i]]+1;
               }
               else
               {
                   CUrLEn++;
               }
               visit[str[i]]=i;
           }
           if(CUrLEn>MAxLEn)
           {
               MAxLEn=CUrLEn;
               BEgin=lastBEgin;
           }
       }
       for(int i=BEgin;i<BEgin+MAxLEn;i++)
       {
           cout<<str[i];
       }
       cout<<endl;
       return MAxLEn;
    
    }

    时间复杂度:O(n)

    4.使用后缀数组,个人觉得这种最好理解(首先要理解后缀数组是啥,前缀数组是啥)
    计算每个后缀数组的不重复的前缀数组的长度,然后比较求最长的那个长度就可以了。

    int GEtLOngestDiLEn(char* str)
    {
       int hash[256];
       int LEn=0;
       memset(hash,0,sizeof(hash));
       while(*str&&!hash[*str])
       {
           LEn++;
           hash[*str]=1;
           str++;
       }
       return LEn;
    }
    int GEtDIfNUm5(char* str)
    {
       int MAxLEn=0;
       int CUrLEn;
       int n=strlen(str);
       int BEgin;
       for(int i=0;i<n;i++)
       {
           CUrLEn=GEtLOngestDiLEn(&str[i]);
           if(CUrLEn>MAxLEn)
           {
               MAxLEn=CUrLEn;
               BEgin=i;
           }
       }
       for(int i=BEgin;i<BEgin+MAxLEn;i++)
       {
           cout<<str[i];
       }
       cout<<endl;
       return MAxLEn;
    }

    时间复杂度:O(n^2)

    主要借鉴了下面的文章

    /*
    http://blog.csdn.net/insistgogo/article/details/7830972
    http://www.cnblogs.com/luxiaoxun/archive/2012/10/02/2710471.html
    */



  • 相关阅读:
    转:SQL Case when 的使用方法
    转:性能测试知多少
    转:如何让LoadRunner实现多个场景运行?
    转:Loadrunner学习知多少--脚本录制下载操作
    1.3 本章小结
    1.2.5 内部元数据
    1.2.4 创建图像查看应用程序
    1.2.3 使用MediaStore检索图像
    1.2.2 更新CameraActivity以使用MediaStore存储图像和关联元数据
    1.2.1 获得图像的Uri
  • 原文地址:https://www.cnblogs.com/peterleee/p/9373768.html
Copyright © 2011-2022 走看看