问题描述
给定一字符串数组 szText,将其中的所有空格替换为 "%20" 字符串。(注:szText 数组后面拥有足够长的额外空余空间)
解题
思路一
该问题最最普通的解法就是从前往后逐一扫描,遇到某位置Pos处的字符为空格时,将 Pos 之后的所有字符全部分别向后面移动2格。直至将整串数组的有效部分全部扫描完毕。
明显的,该方案虽然可行,但需嵌套循环(一个用于遍历,一个用于移动),所以在最坏情况下,时间复杂度为 O(N2)。
思路二
由于 szText 末尾拥有足够多的额外空余空间,因此,如果能够事先知道 szText 字符串数组中的空格总个数,即可知道最终替换完成后的字符串的总的长度是多少。然后即可从 szText 的最后一个字符逐一往前扫描遍历,只要字符非空格,则将该字符移到最终替换完成后的字符串的相应位置,如果是空格字符,则用 '%' '2' '0' 三个字符填充即可。具体执行步骤描述如下:
不妨假设 szText 数组的字符串长度为 nTextLen,空格总个数为 nWhiteSpaceCounter,则替换后的字符串的长度为 nTextLen + nWhiteSpaceCounter * (3 - 1)
1) 分设置两标记,nIndex 指向 szText 数组原字符串的末尾;以及 nFinalTextPos 指向最终替换后字符串的末尾
2) 如果 nIndex 位置为非空格字符,则将其移到 nFinalTextPos 位置的最终字符串处;
如果 nIndex 位置为空格字符,则将 nFinalTextPos - 3 到 nFinalTextPos - 1 范围内 3 位置分别填充为 '%' '2' '0' 即可;
3) --nIndex;--nFinalTextPos ;重复步骤 2) 直到 nIndex 已经处理完 szText 原始字符串的第一个字符时,算法完成。
该解法,主要要完成两个大的部分,一部分是为了统计总的空格的个数,所以需要一遍扫描处理,该部分耗时 O(n),接下来是遍历原字符串,并进行字符移动操作,因此也需要 O(n),故该解法的总的时间复杂度为:T = O(N)。具体编码实现参考如下:
1 int ReplaceWhiteSpace::replaceWhiteSpace(char strText[], const int nTextLen) { 2 auto nRetLength = nTextLen; 3 4 auto nWhiteSpaceNumber = 0; 5 for (auto nIndex = 0; nIndex < nTextLen; ++nIndex) { 6 if (' ' == strText[nIndex]) { 7 ++nWhiteSpaceNumber; 8 } 9 } 10 const auto nFinalTextLen = nTextLen + nWhiteSpaceNumber * 2; // 因为每一个空格被替换为 %20 这是3个字会,于是就多出2个字符 11 nRetLength = nFinalTextLen; 12 13 auto nFinalTextPos = nFinalTextLen; 14 for (auto nIndex = nTextLen - 1; nIndex >= 0; --nIndex) { 15 if (' ' == strText[nIndex]) { 16 strText[--nFinalTextPos] = '0'; 17 strText[--nFinalTextPos] = '2'; 18 strText[--nFinalTextPos] = '%%'; 19 } else { 20 strText[--nFinalTextPos] = strText[nIndex]; 21 } 22 } 23 24 return nRetLength; 25 } 26 27 28 int _tmain(int argc, _TCHAR* argv[]) 29 { 30 //nsalgorithm::ValidateProjectConfig::validate("log/ReplaceWhiteSpaces/testlog"); 31 32 { // 测试用例 33 34 const auto nArrayTotalLen = 1024; 35 char szText[nArrayTotalLen] = "This is a test. Hello world!"; 36 const auto nTextLen = strlen(szText); 37 38 nsalgorithm::AlgorithmHelpers::printData(szText, 0, nTextLen - 1); 39 40 nsalgorithm::ReplaceWhiteSpace replaceWhiteSpace; 41 const auto nFinalLength = replaceWhiteSpace.replaceWhiteSpace(szText, nTextLen); // 测试结果 42 43 nsalgorithm::AlgorithmHelpers::printData(szText, 0, nFinalLength - 1); 44 } 45 46 system("pause"); 47 return 0; 48 }
测试结果
问题拓展
如果将题目更改为要将字符串数组中的空格全部替换为指定的任意字符串了?(即:替换的字符串不一定是换成 "%20",可以是任意的字符串,如:"XXXXX",甚至是空符串 "")。因此,沿用上面的思路二,问题,只需要 O(nm)时间复杂度即可完成。其中 n 为原字符串的长度,m 为替换的字符串的长度,因为替换的字符串都是明确且固定的,因此,m可以认为是一个常量系数,因此算法的时间复杂度仍为 O(n)。
算法实现代码参考如下:
1 int ReplaceWhiteSpace::replaceWhiteSpace(char strText[], const int nTextLen, const char* const pcszReplaceStr) { 2 auto nRetLength = nTextLen; // default return value. 3 4 if (nullptr == pcszReplaceStr) { 5 return nRetLength; 6 } 7 8 const int nReplaceStrLength = static_cast<int>(strlen(pcszReplaceStr)); 9 auto nModifyPos = 0; // 用于标记 pcszReplaceStr 长度 <= 1 的情况下的 strText 的 修改的位置 10 auto nWhiteSpaceCounter = 0; // 用于统计总的空格的个数 11 for (auto nIndex = 0; nIndex < nTextLen; ++nIndex) { 12 if (' ' == strText[nIndex]) { 13 switch (nReplaceStrLength) { 14 case 0 : strText[nModifyPos] = strText[nIndex]; break; 15 case 1 : strText[nModifyPos] = *pcszReplaceStr; ++nModifyPos; break; 16 default: ++nWhiteSpaceCounter; break; 17 } 18 } else if (nReplaceStrLength <= 1) { 19 if (nModifyPos != nIndex) { 20 strText[nModifyPos] = strText[nIndex]; 21 } 22 ++nModifyPos; 23 } 24 nRetLength = nModifyPos; 25 } 26 27 if (nReplaceStrLength > 1) { 28 nRetLength = nTextLen + nWhiteSpaceCounter * (nReplaceStrLength - 1); 29 auto nFinalWritePos = nRetLength; 30 for (auto nIndex = nTextLen - 1; nIndex >= 0; --nIndex) { 31 if (' ' == strText[nIndex]) { 32 auto nReplaceStrPos = nReplaceStrLength; 33 while (--nReplaceStrPos >= 0) { 34 strText[--nFinalWritePos] = *(pcszReplaceStr + nReplaceStrPos); 35 } 36 } else { 37 strText[--nFinalWritePos] = strText[nIndex]; 38 } 39 } 40 } 41 42 return nRetLength; 43 } 44 45 int _tmain(int argc, _TCHAR* argv[]) 46 { 47 //nsalgorithm::ValidateProjectConfig::validate("log/ReplaceWhiteSpaces/testlog"); 48 49 { // 测试用例 50 51 const auto nArrayTotalLen = 1024; 52 char szText[nArrayTotalLen] = "This is a test. Hello world!"; 53 const auto nTextLen = strlen(szText); 54 nsalgorithm::AlgorithmHelpers::printData(szText, 0, nTextLen - 1); 55 56 nsalgorithm::ReplaceWhiteSpace replaceWhiteSpace; 57 const auto nFinalLength = replaceWhiteSpace.replaceWhiteSpace(szText, nTextLen, "%20"); // test ok 58 nsalgorithm::AlgorithmHelpers::printData(szText, 0, nFinalLength - 1); 59 60 char szText2[nArrayTotalLen] = "This is a test. Hello world!"; 61 const auto nTextLen2 = strlen(szText2); 62 const auto nFinalLength2 = replaceWhiteSpace.replaceWhiteSpace(szText2, nTextLen2, "%"); // test ok 63 nsalgorithm::AlgorithmHelpers::printData(szText2, 0, nFinalLength2 - 1); 64 65 char szText3[nArrayTotalLen] = "This is a test. Hello world!"; 66 const auto nTextLen3 = strlen(szText3); 67 const auto nFinalLength3 = replaceWhiteSpace.replaceWhiteSpace(szText3, nTextLen3, ""); // test Ok 68 nsalgorithm::AlgorithmHelpers::printData(szText3, 0, nFinalLength3 - 1); 69 } 70 71 72 system("pause"); 73 return 0; 74 }
测试结果