字符串笔面试题

一、把一个字符串向左/右循环移位n个。如abcdefghi,向左循环移位2个,结果为cdefghiab。

    这题的出现概率较大,难度较小

1)如果没有空间的限制,那么第一个容易想到的解法是,申请一个strlen长的字符串数组,把字符串复制到这一数组,然后依照移位前后数组序号的关系,确定移位后的字符串。移位后的数字序号是未移位+n(移位距离),循环所以要%strlen

char* rLeftfour(char * str,int n)
{
    int slen=strlen(str);
    n%=slen;                      //循环左移位
    //n=slen-n%slen;          //循环右移位
    char *temp=new char[slen];
    for (int i=0;i<slen;i++)
        temp[i]=str[i];
    for (int j=0;j<slen;j++)
          str[j]=temp[(j+n)%slen];
    return str;
}

2)假设只能申请一个字节的额外空间,时间没有限制。那么可以对上述算法改进,每次只循环移动一位,总共循环n次。循环一位的时候,只需要保存第一个字符就行,后面的字符依次复制上来,然后把第一个字符复制到最后。

char* rLefttwo(char * str,int n)
{
    int slen=strlen(str);
    n%=slen;                   //循环左移位
    //n=slen-n%slen;          //循环右移位
    for (int i=0;i<n;i++)
    {   
        char temp=str[0];
        for (int j=0;j<slen-1;j++)
            str[j]=str[j+1];
        str[slen-1]=temp;    

    }
    return str;
}

3)在1)中申请空间可以缩小,只要保存移位的前n个字符即可,把后面依次复制到前面,最后把保存的字符复制到最后,

char* rLeftone(char * str,int n)
{
    int slen=strlen(str);
    n%=slen;               //循环左移位,等于数组长时相当于没有移位
    //n=slen-n%slen;          //循环右移位
    char *temp=new char[n];
    for (int i=0;i<n;i++)
        temp[i]=str[i];
    for (int j=n;j<slen;j++)
        str[j-n]=str[j];
    for (int k=0;k<n;k++)
        str[slen-n+k]=temp[k];
    return str;
}

4)来自于编程珠玑,思想是把原始字符串分成ab两部分,a是前i个元素,b是后n-i个元素,首先对a逆序,得到a-1b,然后对b逆序得到a-1b-1,然后对整体逆序得到(a-1b-1-1=ba。

char* rLeftthree(char * str,int n)
{
    int slen=strlen(str);
    n%=slen;               //循环左移位
    //n=slen-n%slen;          //循环右移位
    reverse(str,0,n-1);
    reverse(str,n,slen-1);
    reverse(str,0,slen-1);
    return str;
}
char* rLeftfour(char * str,int n)
{
    int slen=strlen(str);
    n%=slen;               //循环左移位
    //n=slen-n%slen;          //循环右移位
    char *temp=new char[slen];
    for (int i=0;i<slen;i++)
        temp[i]=str[i];
    for (int j=0;j<slen;j++)
          str[j]=temp[(j+n)%slen];
    return str;
}

二、翻转字符串的词。如“the sky is blue”,翻转后为“blue is sky the”。要考虑字符串开头和结尾可能有空格。

1)考虑额外的存储空间,保存字符串的每个单词于一个二维数组中,每行一个单词,开头结尾的空格也存储,然后从数组的尾扫描到头输出即可。

#include <iostream>
using namespace std;
const int row=20;
const int col=20;
void reverse(char *&s)
{
    char *ss=new char[row*col](); 
    char **temp=new char *[row];//新建二维数组存储字符串中单词
    int j=0,k=0,m=0;
    for (int i=0;i<row;i++)
    {
        temp[i]=new char[col]();
    }
    for (int i=0;s[i]!='';i++)
    {
        temp[j][k]=s[i];    
        k++;
        if (s[i]==' ')    //扫描字符串遇到空格,存到数组下一行,如果是开头的空格也一样处理,空间要求大
        {
            j++;
            temp[j][k]='';    
            k=0;
        }
        
    }
    temp[j][k]=' ';//处理最后一个单词
    k++;
    temp[j][k]='';

    for (int i=j;i>=0;i--)
    {
        int k;
       for ( k=0;temp[i][k]!='';k++)
       {
           if (temp[i][k]==' ')  //遇到空格跳出
               break;
           else
           {
               ss[m]=temp[i][k];
               m++; 
           }
          
       } 
       if (k>0)
       {
           ss[m]=' ';//不是开头结尾的加空格
            m++;
       }
       
    }
    ss[m-1]='';
    cout<<ss<<endl; 
    s=ss;
}
int main()
{
    char *s=new char[row*col];
    s=" hello world! we are one   ";
    reverse(s);
    cout<<s;
}

   

 程序是将单词加空格后存成字符串,先分配内存后,扫描字符串,先存,不管是空格还是字符,若第二个是空格或者扫到空格的位置(因为是先存所以单词后都有空格),就到二维数组的下一行,直到字符串处理完毕。接着从二维数组的尾行开始,输出,若存的第一个是空格,忽略,然后把二维数组的单词输出到字符串中,每个单词间加空格。

C++程序

#include <iostream>
#include <string>
using namespace std;
void reverseWords(string &s)
{
    string rs;
    for (int i = s.length()-1; i >= 0; )
    {
        while (i >= 0 && s[i] == ' ') i--;
        if (i < 0) break;
        if (!rs.empty()) rs.push_back(' ');
        string t;
        while (i >= 0 && s[i] != ' ') t.push_back(s[i--]);
        reverse(t.begin(), t.end());
        //t.push_back(' ');
        rs.append(t);
    }
    s = rs;
}
    int main()
    {
        string s=" hello world! ";
        
        reverseWords(s);
        cout<<s;
    }

      

      从后扫描,遇到空格则跳过,定义一个中间变量t来存单词,到空格时,把存的字符串翻转,成!dlrow,加到rs末,跳过空格,加空格在单词间。在最后一个单词时,i<0.不会加空格。

2)利用字符串的翻转,先对整个字符串翻转,然后对字符串中的单词翻转。

#include <iostream>
using namespace std;
void Reverse(char *pBegin,char  *pEnd)
{
    if(pBegin == NULL || pEnd == NULL)
    return ;
while(pBegin < pEnd)
{
    char temp = *pBegin;
       *pBegin = *pEnd;
       *pEnd = temp;
       pBegin ++, pEnd --;
}
}
char* ReverseSentence(char *pData)
{
    if(pData == NULL)
        return NULL;

    char *pBegin = pData;

    char *pEnd = pData;
    while(*pEnd != '')
        pEnd ++;
    pEnd--;

    // Reverse the whole sentence
    Reverse(pBegin, pEnd);

    // Reverse every word in the sentence
    pBegin = pEnd = pData;
    while(*pBegin != '')
    {
        if(*pBegin == ' ')
        {
            pBegin ++;
            pEnd ++;
        }
        else if(*pEnd == ' ' || *pEnd == '')
        {
            Reverse(pBegin, --pEnd);
            pBegin = ++pEnd;
        }
        else
        {
            pEnd ++;
        }
    }

    return pData;
}
int main()
{
    char pstr[]="   hello world!   ";
    cout<<ReverseSentence(pstr);
}

     翻转整个字符串比较好理解,翻转词时,是定义了两个指针,一个指向词头,开始若是空格,两指针一起走,当不是空格时,end的指针向前走,走到空格后者尾时,翻转begin到end间字符,翻转后,要把begin指针移动到end位置,然后一起走,重复。类似上面,其实这题主要的难点在怎么处理那些头和尾的空格。上述代码没有处理空格。想处理空格应该也不难,在翻转后保存词,并加空格

原文地址:https://www.cnblogs.com/dawnminghuang/p/3942695.html