面试题之_00(旋转字符串)

来源:互联网 发布:喜马拉雅有mac版吗 编辑:程序博客网 时间:2024/05/29 02:08

本题目选自July大神编程艺术一书:https://github.com/julycoding/The-Art-Of-Programming-By-July/tree/master/ebook/zh

题目描述

给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。


这一题其实是《编程珠玑》第2章里的一道题目,当时看到这道题觉得给的第三种方法非常巧妙,也非常朴素。可是过了一个月再在july大神的博客看到这道题时,完全又忘记了当时的解法了。所以这就是我要开始写技术博客的原因了,当时看书时纯粹是被动的学习,而写博客是属于主动的学习,博客可以将自己的思考过程全部记录了下来。


三种解法:

解法1:暴力法,将前k个元素复制到一个临时数组,将剩余的元素左移k个位置,最后将临时数组复制到剩下的位置。此方法的一个变种是定义一个函数将str向左旋转一个位置,然后重复调用该函数k次。前者空间复杂度不符合要求,后者时间复杂度不符合要求。


解法2:移动str[0]到临时变量t,然后移动str[k]至str[0],str[2k]至str[k],如果str[i*k]的下标i*k>n,则将下标对n取模。依次类推,直至返回到取str[0]的元素,此时改为从t取值然后终止。如果该过程还没有移动全部元素,就从str[1]开始重复以上过程,直到所有元素都已经移动为止。


解法3:一个朴素的代数思想,将str分成前段a和后段b,即str = ab,对a、b分别求逆,str_temp = a’b‘,再对str_temp求逆,有str_temp’ = ba,即为所求。

void LeftShiftString(char* s, int n, int k){   //边界检查,略    reverse(s, 0, k-1) ;  //转置前k个元素    reverse(s, k, n);      //转置后n-k个元素    reverse(s, 0, n) ;     //转置整个数组}void reverse(char* s, int start, int end) { //用来转置从start开始到end的元素    //边界检查,略   while(start < end)   {      char t = s[start];      s[start] = s[end];      s[end] = t;      start++;end--;   }}
时间复杂度为 O(k)+O(n-k)+O(n) = O(n),空间复杂度为O(1)

0 0
原创粉丝点击