题目描述
给定一个字符串,要求把字符串前面的若干个字符移动到字符串的尾部,如把字符串“abcdef”前面的2个字符'a'和'b'移动到字符串的尾部,使得原字符串变成字符串“cdefab”。请写一个函数完成此功能,要求对长度为n的字符串操作的时间复杂度为 O(n),空间复杂度为 O(1)。
三步反转法
对于这个问题,换一个角度思考一下。
将一个字符串分成X和Y两个部分,在每部分字符串上定义反转操作,如X^T,即把X的所有字符反转(如,X="abc",那么X^T="cba"),那么就得到下面的结论:(X^TY^T)^T=YX,显然就解决了字符串的反转问题。
例如,字符串 abcdef ,若要让def翻转到abc的前头,只要按照下述3个步骤操作即可:
- 首先将原字符串分为两个部分,即X:abc,Y:def;
- 将X反转,X->X^T,即得:abc->cba;将Y反转,Y->Y^T,即得:def->fed。
- 反转上述步骤得到的结果字符串X^TY^T,即反转字符串cbafed的两部分(cba和fed)给予反转,cbafed得到defabc,形式化表示为(X^TY^T)^T=YX,这就实现了整个反转。
void reverse(char *str, int from, int to) { int n = strlen(str); while(from >= 0 && to < n && from < to) { char temp = str[from]; str[from++] = str[to]; str[to--] = temp; } } void LeftRotateString(char *str, int m) { if(m < 1) return; int n = strlen(str); reverse(str, 0, m - 1); reverse(str, m, n - 1); reverse(str, 0, n - 1); }
类似题目:
给定一个List,两个int值,要求翻转这个链表的第i个到第j个元素之间链表段
比如给定{1,2,3,4,5,6},1,3,得到3,2,1,4,5,6
代码如下:(使用头插法,但是注意这里由于未必从头结点开始所以单独加入一个头结点可以简化操作,)
//这里有头结点,对于有头结点的话部分和完全倒置的代码可以一样,没有头结点还要加条件 ListNode* reverse(ListNode *root, int start, int end) { // ListNode *newroot = new ListNode(0); newroot->next = root; root = newroot; ListNode* now = root->next, *pri = root; for(int i = 1; i < start; ++i) { pri = now; now = now->next; } //pri = now; ListNode* mov = now->next; for(int i = start; i < end; ++i) { mov = now->next; now->next = mov->next; mov->next = pri->next; pri->next = mov; } root = root->next; return root; }
翻转所有的结点:
ListNode* reverseAll(ListNode *root) { if(!root) { return NULL; } ListNode *pri = root, *now = root->next; while(now != NULL) { //pri->next = now->next; ListNode *temp = now->next; now->next = pri; pri = now; now = temp; } root->next = NULL; return pri; }
2、编写程序,在原字符串中把字符串尾部的m个字符移动到字符串的头部,要求:长度为n的字符串操作时间复杂度为O(n),空间复杂度为O(1)。 例如,原字符串为”Ilovebaofeng”,m=7,输出结果为:”baofengIlove”。
void rightRotateString(char *str, int m) { if(m < 1) return ; int n = strlen(str); reverse(str, 0, n - m - 1); reverse(str, n - m, n - 1); reverse(str, 0, n - 1); }
3、单词翻转。输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变,句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。例如,输入“I am a student.”,则输出“student. a am I”。可以使用类似的方法或者使用stringstream
void reverseWords(char *word) { int start = 0, end = 0; int size = strlen(word); for(int i = 0; i < size; ++i) { if(word[i] != ' ' && i != size - 1) continue; else { end = i - 1; reverse(word, start, end); start = i + 1; } } reverse(word, 0, size - 1); }
void reverseWords(string &s) { istringstream is(s); string tmp; is >> s; while(is >> tmp) s = tmp + " " + s; if(s[0] == ' ') s = ""; }
void reverseWords(string &s) { istringstream iss(s); string temp; vector<string> str; while (iss >> temp){ str.push_back(temp); } s = ""; //cout << str[0] << 1233 << endl; ostringstream oss; for (size_t i = 0; i < str.size(); ++i){ oss << str[str.size() - i - 1] << " "; } oss.flush(); s = oss.str(); s = s.substr(0, s.size() - 1); }
题目来自:https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh