《算法之美》の字符串相关问题の壹

来源:互联网 发布:数学高一必修三算法 编辑:程序博客网 时间:2024/05/08 15:12

题目:编写一个单词逆序输出的算法,例如输入“SEE YOU IN ANOTHER LIFE”,要求输出“LIFE ANOTHER IN YOU SEE”。

解答:

解法一:只需扫描一遍:

#include <iostream>

void ReverseWord(const char* src, char* dest)

{

          assert(src != NULL && dest != NULL);

     const char* head = src; //记住头指针

     while(*src++);

     int count = 0;

     for(src -= 2;;src--) //从尾到头遍历

     {

         if(src == head) //到头部额,退出循环

         {

              do

              {

                  *dest++ = *src++;

              } while(count--);

              break;

         }

         if(*src == ' ') //遇到空格

         {

             const char* temp = src + 1;

             while(count--)

             {

                 *dest++ = *temp++;             

             }

             *dest++ = ' ';

             count = 0;

         }

         else

         {

             count++;   //计算每个单词的长度

         }

     }

     *dest = '/0';

}

 

int main()

{

    const char* str = "SEE YOU IN ANOTHER LIFE";

    char *dest = new char[strlen(str) + 1];

    ReverseWord(str, dest);   

    std::cout<<str<<std::endl;

    std::cout<<dest<<std::endl;

    system("pause");

    return 0;

}

 

解法二:扫描两遍。即简单地将所有字符反转,遍历字符串,将第一个字符和最后一个字符交换,第二个和倒数第二个交换,依次循环。接着进行第二次遍历,对每个单词反转一次,这样每个单词就恢复成原有顺序,得到题目要求的功能了:

#include <iostream>

 

char* ReverseWord(const char* str)

{

    assert(str != NULL);

    int len = strlen(str);

    char* restr = new char[len + 1];

    strcpy(restr, str);

   

    //第一次扫描,头尾反转

    for(int i=0, j=len-1; i<j; i++,j--)

    {

        //首尾交换

        restr[i] ^= restr[j];

        restr[j] ^= restr[i];

        restr[i] ^= restr[j];

    }

    int k = 0;

    while(k < len) //第二次扫描,将每个单词反转

    {

        int i, j; //i记录每个单词开始位置,j记录每个单词结束位置

        i = j = k;

        while(restr[j] != ' ' && restr[j] != '/0')

        {

            j++;              

        }

       

        k = j+1; //为跳过空格,为下一轮循环做准备

        j--; //回退一步,去掉空格

        for(;i<j; i++, j--)

        {

            restr[i] ^= restr[j];

            restr[j] ^= restr[i];

            restr[i] ^= restr[j]; 

        }

    }

   

    return restr;

}

 

int main()

{

    const char* str = "SEE YOU IN ANOTHER LIFE";

    char *dest = ReverseWord(str);

    std::cout<<str<<std::endl;

    std::cout<<dest<<std::endl;

    system("pause");

    return 0;   

}

 

 

题目:给定一个字符串,一个这个字符串的子串,将第一个字符串反转,但保留子串的顺序不变。例如:

输入:第一个字符串:“See you in another life

           子串:“in

输出:“efil rehtona in uoy eeS

 

解答:一般的方法是先扫描一遍第一个字符串,用stack把它反转,同时记录下子串出现的位置;然后再扫描一遍反转后的字符串,扫描过程中将原来子串再反转,其他的不变,这样就得到答案了。

那么只扫描一遍怎么办呢?只需在扫描的过程中将子串反序压入堆栈;扫描完之后,将堆栈中字符弹出,这样子串就还是原来的顺序了。实现代码如下:

 

#include <iostream>

#include <cassert>

#include <stack>

 

const char* reverse(const char* s1, const char* token)

{

    assert(s1 && token);

    std::stack<char> stackOne;

    const char* ptoken = token;

    const char* head = s1;

    const char* rear = s1;

   

    while(*head != '/0')

    {

        while(*head != '/0' && *ptoken == *head)

        {

            ptoken++;

            head++;           

        }

        if(*ptoken == '/0') //包含字符串token

        {

            const char* p;

            for(p=head-1; p>=rear; p--) //从尾到头将token存入堆栈

            {

                stackOne.push(*p);             

            }         

            ptoken = token;

            rear = head;

        }

        else //不是分割的字符串

        {

            stackOne.push(*rear);

            head = ++rear;

            ptoken = token;  

        }

    }

   

    char* ret = new char[strlen(s1)+1];

    int i = 0;

    while(!stackOne.empty()) //非空

    {

        ret[i++] = stackOne.top();

        stackOne.pop();

    }    

    ret[i] = '/0';

    return ret;

}

 

int main()

{

    std::cout<<"See you in another life"<<std::endl;

    std::cout<<reverse("See you in another life", "in")<<std::endl;

   

    system("pause");

    return 0;

}