面试题 42(*),翻转单词顺序,字符串的左旋转 (字符串操作类经典题目:两次Reverse字符串的妙用,可以做到不需要额外空间的情况下按要求变换顺序)

看了书里的提示才想到:两次翻转字符串。
这是非常经典的题目,解法也非常经典。
先把字符串整个逆序一遍,然后再将里面被空格分开的子字符串挨个逆序一遍,就得到要求的字符串了。
自己实现的代码:
#include <string.h> #include <stdio.h> void ReverseStr(char* str, char* end){ for(; str < end; str++, end--){ char temp = *str; *str = *end; *end = temp; } } void ReverseWord(char* str){ if(str == NULL || *str == '\0') return; char* p = str; while(*p != '\0') p++; ReverseStr(str, p-1); p = str; char* start = str; while(*p != '\0'){ for(; *p != ' ' && *p != '\0'; p++); ReverseStr(start, p - 1); if(*p != '\0'){ p++; start = p; } } } // ====================测试代码==================== void Test(char* testName, char* input, char* expectedResult) { if(testName != NULL) printf("%s begins: ", testName); ReverseWord(input); if((input == NULL && expectedResult == NULL) || (input != NULL && strcmp(input, expectedResult) == 0)) printf("Passed.\n\n"); else printf("Failed.\n\n"); } // 功能测试,句子中有多个单词 void Test1() { char input[] = "I am a student."; char expected[] = "student. a am I"; Test("Test1", input, expected); } // 功能测试,句子中只有一个单词 void Test2() { char input[] = "Wonderful"; char expected[] = "Wonderful"; Test("Test2", input, expected); } // 鲁棒性测试 void Test3() { Test("Test3", NULL, NULL); } // 边界值测试,测试空字符串 void Test4() { Test("Test4", "", ""); } // 边界值测试,字符串中只有空格 void Test5() { char input[] = " "; char expected[] = " "; Test("Test5", input, expected); } int main() { Test1(); Test2(); Test3(); Test4(); Test5(); return 0; }
书上的代码:
char* ReverseSentence(char *pData) { if(pData == NULL) return NULL; char *pBegin = pData; char *pEnd = pData; while(*pEnd != '\0') pEnd ++; pEnd--; // 翻转整个句子 Reverse(pBegin, pEnd); // 翻转句子中的每个单词 pBegin = pEnd = pData; while(*pBegin != '\0') { if(*pBegin == ' ') { pBegin ++; pEnd ++; } else if(*pEnd == ' ' || *pEnd == '\0') { Reverse(pBegin, --pEnd); pBegin = ++pEnd; } else { pEnd ++; } } return pData; }
接着,另一道题:

这道题其实是上一题的变种,其实也就是将字符串的各部分换个位置。只不过划分部分的标志不再是空格,而是人为制定的字符个数。
我们依然将整个字符串先逆序,然后要求左旋转N位,就将逆序后的后N位逆序,前半部分也逆序,结束。
这里代码就不提供了,直接上书上的代码:
#include "stdafx.h" #include "..\Utilities\StringUtil.h" #include <string.h> char* LeftRotateString(char* pStr, int n) { if(pStr != NULL) { int nLength = static_cast<int>(strlen(pStr)); if(nLength > 0 && n > 0 && n < nLength) { char* pFirstStart = pStr; char* pFirstEnd = pStr + n - 1; char* pSecondStart = pStr + n; char* pSecondEnd = pStr + nLength - 1; // 翻转字符串的前面n个字符 Reverse(pFirstStart, pFirstEnd); // 翻转字符串的后面部分 Reverse(pSecondStart, pSecondEnd); // 翻转整个字符串 Reverse(pFirstStart, pSecondEnd); } } return pStr; } // ====================测试代码==================== void Test(char* testName, char* input, int num, char* expectedResult) { if(testName != NULL) printf("%s begins: ", testName); char* result = LeftRotateString(input, num); if((input == NULL && expectedResult == NULL) || (input != NULL && strcmp(result, expectedResult) == 0)) printf("Passed.\n\n"); else printf("Failed.\n\n"); } // 功能测试 void Test1() { char input[] = "abcdefg"; char expected[] = "cdefgab"; Test("Test1", input, 2, expected); } // 边界值测试 void Test2() { char input[] = "abcdefg"; char expected[] = "bcdefga"; Test("Test2", input, 1, expected); } // 边界值测试 void Test3() { char input[] = "abcdefg"; char expected[] = "gabcdef"; Test("Test3", input, 6, expected); } // 鲁棒性测试 void Test4() { Test("Test4", NULL, 6, NULL); } // 鲁棒性测试 void Test5() { char input[] = "abcdefg"; char expected[] = "abcdefg"; Test("Test5", input, 0, expected); } // 鲁棒性测试 void Test6() { char input[] = "abcdefg"; char expected[] = "abcdefg"; Test("Test6", input, 7, expected); } int _tmain(int argc, _TCHAR* argv[]) { Test1(); Test2(); Test3(); Test4(); Test5(); Test6(); return 0; }
总结:遇到这种要求字符串内部顺序变换的题目,尽量多从Reverse考虑,因为(1) 这种顺序的变换往往可以由Reverse的组合实现 (2) Reverse是唯一不需要额外空间的做法,大部分不需要额外空间的最优解,都是顺着这个思路下去的。
------------------------------------------------
Felix原创,转载请注明出处,感谢博客园!
posted on 2014-03-03 04:48 Felix Fang 阅读(260) 评论(0) 收藏 举报
浙公网安备 33010602011771号