致我们终将忘记的算法(随处可见的经典)

1->求字符串中重复出现的最长子串(例如:字符串drgabcdeabcfh中,最长重复出现的子串为:abc)

解题方法:利用后缀树来求解:

字符串的后缀树:(对于字符串abcd来说:abcd、bcd、cd、d)那么要求字符串中出现的最长重复子串,就是找出后缀树中的最长公共前缀

int commStr(string str1,string str2){        //求两个字符串的公共前缀的长度

    int len=(str1.size()>str2.size()?str2.size():str1.size());

    int i=0;

    while(i<len && str1[i]==str2[i])  i++;

    return i;

}

void maxSub(sting& str,string &key){

    int len=str.length();

    string *sub=new string[len];

    for(int i=0;i<len;i++)    sub[i]=str.substr(i);

    sort(sub,sub+len);

    int max=1;

    for(int i=1;i<len;i++){

        int countcur=commStr(str[i],str[i-1]);

        if(max<countcur){key=sub[i].substr(0,countcur); max=countcur;}

    }

}

2->素数和分解(一个整数可以分解成若干素数的和,输入一个整数,试求出所有可能的分解)

bool isPrime(int n){                  //判断一个数是否是素数

    int i=2;

    for(;i*i<=n;i++){

          if(n%i==0) return false;

    }

    return true;

}

void generate(int n,vector<int>& prime){               //生成n以内的素数,并保存在prime内

    prime.push(2);

    for(int i=3;i<n;i++){

         if(isPrime(i))  prime.push_back(i);

    }

}

void helper(int n,int cur,vector<int>& prime){

    static vector<int>  result;

    if(n<0)  return ;

    if(n==0){Print(result.begin(),result.end());}

    for(int i=cur;i<prime.size();i++){

        result.push_back(prime[i]);

        helper(n-prime[i],i,prime);

        result.pop_back();

    }

}

3->判断一个数是否是平方数

解题方法:二分法

int isSqrt(int n,int low,int high){

    if(n==0)    return 0;

    if(low<high){

         int mid=(low+high)/2;

         if(mid*mid==n)

                   return mid;

         if(mid*mid<n)  return isSqrt(n,mid+1,high);

         else return isSqrt(n,low,mid);

    }

    return -1;

}

4->N的拆分

解题方法:DFS方法可以搞定

void cutN(int n,vector<int>& v){

    if(n==0){

         Print(v.begin(),v.end());

    }else{

         for(int i=1;i<=n;i++){

               v.push_back(i);   cutN(n-i,v); v.pop_back();

         }

    }

}

5->RGB序列(如果一个字符串是由RGB三个字母随机组成的,那么试将所有的R移动到字符串的左端,B移动到字符串的右端,G在字符串的中部)

解题方法:本题跟一个数组的奇数和偶数分开类似,起初可以将GB看成一种情况,将R和GB分开,之后再分割GB

void SpliceRGB(char *& str){

    char* start,*end;

    start=end=str;

    while(*start=='R'  && *start!='\0') start++;

    if(*start=='\0')  return ;

    end=start;

    while(*end!='\0'){

        if(*end=='R'){

              char ch=*start;   *start=*end;  *end=ch;  while(*start=='R') start++;

        }

        end++;

    }

    //将BG分开

    end--;

    while(start<end){

         if(*start=='G') start++;

         if(*end=='B') end--;

         if(*start=='B' && *end=='G' && start<end){

                   swap(*start,*end);  start++; end--;

         }

    }   

}

6->删除字符串开始以及末尾的空白符,并且把单词间的空格压缩

解题方法:这一题和数组删除某个元素有相似之处。

void changeStr(string &s){

    string::iterator p1=find_first_not_of(s.begin(),s.end(),' ');

    string::iterator p2=find_last_not_of(s.begin(),s.end(),' ');

    s.substr(p1,p2);

    string::iterator p=s.begin();

    int index=0; int flag=1;

    while(p!=s.end()){

       if(*p!=' '){ s[index++]=*p;flag=1;}

       else { if(flag==1){ s[index++]=*p; flag=0;}}

       p++;

    }

}

7->字符串移动(字符串为*和26个字母的组合,把*移到最左侧,把字母移到最右侧并且保持相对位置不变)

void partitionStr(char *str){

    int len=strlen(str);

    int i=str+len,j=str+len;

   while(i>=0){

       if(str[i]!='*') { swap(str ,i--,j--);}

       else i--;

  }

}

8->有一个单向循环链表,从头开始如果到第m个就开始出队,如此循环直到最后一个元素。再把所有出队的元素链接成一个新的链表。

ListNode* recorder(ListNode *head,int m){

    ListNode *p,*pre,*tail;

    p=head;

    ListNode *newHead=new ListNode(-1);     //新的链表的辅助头结点

    tail=newHead;

    int count=1;

    while(p->next!=p){

           count++;   pre=p;   p=p->next;

           if(count%m==0){

                  pre->next=p->next;    //将p点从原表中断开

                  tail->next=p;  tail=p;      //将p结点链接到新表

                  p=pre->next;

           }

    }

    tail->next=p;  tail=p;

    tail->next=newHead->next;

    return newHead->next;

}

发布了99 篇原创文章 · 获赞 8 · 访问量 4万+

猜你喜欢

转载自blog.csdn.net/CodeAsWind/article/details/39158161
今日推荐