字符串相关的高频面试题

案例三:如果一个字符串str,把字符串str前面任意部分挪到后面去形成的字符串叫做str的旋转词。判断str1和str2是否互为旋转词。

本题的最优解的时间复杂度为o(n),其中n是str1的长度。

1. 判断str1与str2是否长度相等。如果长度不相等则一定刚不互为旋转词。

2. 如果长度相等,生成str1+str1的大字符串;

3. 用KMP算法判断大字符串中是否函数str2。如果有则互为旋转词。

原因在于如果str1长度为n,在str1+str1的字符串中,任意一个长度为n的子串都是str1的旋转词。

class Rotation
{
public:
  bool
  chkRotation (string A, int lena, string B, int lenb)
  {
    if (lena == 0 || lenb == 0 || lena != lenb) //注意这里不能用A==NULL因为A不是指针,只有数组名即数组的首地址可以直接用来作为指针变量,其他的类型数据的名字都表示他本真的值
      return false;
    string C = A + A;
    //下面是利用KMP算法看B是否在C中
    int* a = getNext (B, lenb);
    int i, j;
    i = 0;
    j = 0;
    bool flag = true;
    while (i < 2 * lena && j < lenb)
      {
if (C[i] == B[j])
 {
   flag = true;
   i++;
   j++;
 }
else if (C[i] != B[j] && j > 0)
 {
   flag = false;
   j = a[j];
 }
else
 {
   i++;
 }
      }
    return flag;
  }
  int*
  getNext (string b, int lenb)
  {
    int* next = new int[lenb + 1];
    int i = 1;
    int j = 0; //表示长度为i的最长前缀后缀公共子串的长度
    next[0] = 0;
    next[1] = 0;
    while (i < lenb)//这里一定要加上j<lenb,否则的话会数组越界
      {
if (b[i] == b[j])
 {
   j++;
   next[i + 1] = j;
   i++;
 }
else if (b[i] != b[j] && j > 0)
 {
   j = next[j];
 }
else
 {
        next[i+1]=j;//这句话非常非常重要的!!!一定不要忘记!!!否则的话如果从一开始就连续的没有相等的话,那么如果没有这句话就会导致好多next[i]都没有被赋值,所以就是错的!!这些实际上都应该是0
   i++;
 }
      }
    return next;


  }


};

上面的KMP算法很重要!!


案例四:给定给一个字符串str,请在单词间做逆序调整。

例子:pig loves dog. 逆序成dog loves pig.

1. 实现将字符串局部所有字符逆序的函数f。

2.利用f将字符串所有字符逆序。

3找到逆序后的字符串中每一个单词的区域,利用f将每一个单词的区域逆序。

class Reverse
{
public:
  string
  reverseSentence (string A, int n)
  {
    // write code here
    int start = 0;
    int len = n;
    inverseOrder (A, start, len);
    cout << A << '\n';
    int lenb;
    int j = 0;
    while (j < n)
      {
if (A[j] != ' ')
 {
   j++;
   continue;
 }
else
 {
   lenb = j;
   inverseOrder (A, start, (lenb - start));
   while (A[j] == ' ')
     j++;
   start = j;
 }
      }
    if (A[j - 1] != ' ') //这一步很重要,因为如果最后是仅为j=n跳出循环,而不是因为遇到了空格,那么就会造成最后一个单词没有被逆序!!!
      inverseOrder (A, start, (j - start));
    cout << A << '\n';
    return A;
  }
  void
  inverseOrder (string& A, int start, int len)
  { //len代表A的长度,也就是含有的字符的数量
    int i = start;
    int b = len + start - 1;
    int temp;
    while (i < b)//注意这里不可以是i!=b这是非常错误的!!!!!假如 i为0  b为19,那么到最后i和b永远不可能相等,只能从b大于i到b小于i!!!!!
      {
temp = A[i];
A[i] = A[b];
A[b] = temp;
i++;
b--;
      }
  }
};

上面是具体的程序,需要注意的是inverseOrder函数中的while循环,条件一定更要注意!!!

案例五:给定给一个字符串str,和一个整数i,i代表str中的位置,将str[0....i]移到右侧,str[i+1,...,N-1]移到左侧。

要求时间复杂度为o(n),额外空间复杂度为o(1)。

1. 将str[0,..i]部分的字符逆序;

2,将str[i+1,...,n-1]部分的字符逆序;

3.将str整体的字符逆序;

class Translation {
public:
    string stringTranslation(string A, int n, int len) {
        // write code here
        //需要空间复杂度为o(1)也就是说不能借用别的数组
        inverseString(A,0,n);//这里面0是起始位置,len是需要逆序的字符串中的字符的数量,也就是字符串的长度
        inverseString(A,0,n-len);
        inverseString(A,n-len,len);
        return A;
    }
    void inverseString(string& C,int start,int len){//注意这里是引用!!!因为没有返回值,就是对字符串操作,所以要用引用
        int temp;
        int i=start;
        int j=len+start-1;
        while(i<j){
            temp=C[i];
            C[i]=C[j];
            C[j]=temp;
            i++;
            j--;
        }
        
   }
};

对于上面的程序来说,inverseString中的string参数一定要用引用的形式!!!如果用对象则对A不会有任何改变!!

案例六:给定给一个字符串类型的数组strs,请找到一种拼接顺序,使得所有字符串拼接起来组成的大字符串是所有可能性中字典顺序最小的,并返回这个大字符串。

最优解的时间复杂度o(n*logn),其实质是一种排序的实现。

如果按照单独每个字符串的字典顺序排序的话,是错误的。比如 ba  b如果按照这种方式进行排序就是bba,但是实际上应该是bab。

正确的方式是如果str1+str2<str2+str1,则str1放在前面,否则str2放在前面。

class Prior {
public:
    string findSmallest(vector<string> strs, int n) {//其实就是排序,只不过比较的方式变了,不是单纯的大于或者小于,而是两个数拼接后的字典序!!!
        // write code here
        string result;
        quicksort(strs,0,n-1);
        vector<string>::iterator iter=strs.begin();
        for(;iter!=strs.end();iter++){
            result=result+*iter;
        }
            return result;
        
    }
    void quicksort(vector<string>& strs,int low,int high){
        if(low<high){
        int pivot=quickpinjie(strs,low,high);
        quicksort(strs,low,pivot-1);
        quicksort(strs,pivot+1,high);
        }
    }
    int quickpinjie(vector<string>& strs,int low,int high){
        string pivot1=strs[low];
        while(low<high){
            while(low<high&&strs[high]+pivot1>pivot1+strs[high])
                high--;
                swap(strs[high],strs[low]);
            while(low<high&&strs[low]+pivot1<=pivot1+strs[low])//需要注意的是这里一定更要有等号,因为如果两个while循环中都没有等号就表示当数组中有和
                //strs[low]相等的元素的时候,程序就会陷入死循环,因为那样的haullow和high就不会改变,就会永远陷在这里。所以一定更要有相等的时候!!
                low++;
                swap(strs[low],strs[high]);    
    }   
        return low;
    }
    void swap(string &a,string &b){
        string temp;
        temp=a;
        a=b;
        b=temp;
    }
};

实际上这道题就是一个排序题,只不过排序的规则有点不同,两个元素不是单纯的依靠大于小于来排序,而是根据str1+str2<str2+str1这个规则来排序!!!所以其实用排序算法就可以,这里使用了快速排序的方式!!


string类对象之间的比较可以用成员函数compare以及> < ==等,区别在于:

compare有多重重载,这些重载允许你将一个字符串的某个子串和另一个字符串比较;
compare的返回类型是int,意味着当字符串相等时,它会返回给你0;当第一个字符串小于第二个字符串时,返回负数,否则返回正数。

而小于号大于号操作符只会返回给你true和false。
 

sort函数中,如果是没有定义小于运算的数据类型,或者想改变排序的顺序,就要用到第三参数——比较函数。比较函数是一个自己定义的函数,返回值是bool型,它规定了什么样的关系才是“小于”。想把刚才的整数数组按降序排列,可以先定义一个比较函数cmp:

bool cmp(int a,int b) {     return a>b; }排序的时候就写sort(a,a+100,cmp);


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值