题目一:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串“I am a student.",则输出"student. a am I"。
思路:《编程珠玑》第二章有类似题目,思路就是先翻转每个单词,然后再翻转整体。
void Reverse(char* pStart, char* pEnd)
{
if(pStart == NULL || pEnd == NULL)
return;
while(pStart < pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
++pStart;
--pEnd;
}
}
void ReverseSentence(char* pStr)
{
if(pStr == NULL)
return;
int length = strlen(pStr);
char *pStart, *pEnd;
pStart = pEnd = pStr;
while(*pStart != '\0')
{
while(*pStart == ' ')
++pStart;
pEnd = pStart;
while(*pEnd != ' ' || *pEnd != '\0')
{
++pEnd;
if(*pEnd == ' ' || *pEnd == '\0')
break;
}
Reverse(pStart, --pEnd);
pStart = ++pEnd;
}
Reverse(pStr, pStr+length-1);
}
题目二:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果“cdefgab"。
思路(1):与题目一类似,可以把前面两位看成一个单词,后面的部分看成另一个单词,那么问题就成了翻转两个单词而单词内的字符顺序不变。仿照上一题的做法,先翻转ab部分得到"bacdefg",再翻转后面的部分得到"bagfedc",最后翻转整体得到"cdefgab”,即完成了两位的左旋转。
char* Rotate(char* pStr, int n)
{
int length = strlen(pStr);
if(pStr != NULL && n > 0 && n < length)
{
char* subStr1Begin = pStr;
char* subStr1End = pStr + n - 1;
char* subStr2Begin = subStr1End + 1;
char* subStr2End = pStr + length - 1;
Reverse(subStr1Begin, subStr1End);
Reverse(subStr2Begin, subStr2End);
Reverse(subStr1Begin, subStr2End);
}
return pStr;
}
思路(2):注意到翻转实际上就是字符的移位,翻转2位就是下标整体向前移动2位,譬如'c'原先的下标为2,翻转后为0。我们把n位上的移到0位上,注意0位上的字符暂时不需要移动,所以保存在一个临时变量中;再把2n位移到n位,3n位移到2n位(所有下标都要取模),直到需要0位时,因为0位已经n位被覆盖,但是先前的值已经保存在临时变量中,把这个临时变量放在新位置中。注意这一过程并不一定所有元素都发生了移动,如果移动的字符小于字符串长度,那么再从第1位开始,n+1位移到1位上……直到所有位都发生了移动。
char* rotate(char* pStr, int n)
{
if(pStr != NULL && n > 0)
{
int length = strlen(pStr);
int countOfSwaped = 0;
int startOfSwap = 0;
int index = startOfSwap;
while(countOfSwaped < length)
{
char temp = pStr[index];
int newIndex = (index+n) % length;
while(newIndex != startOfSwap)
{
pStr[index] = pStr[newIndex];
++countOfSwaped;
index = newIndex;
newIndex = (newIndex+n) % length;
}
pStr[index] = temp;
++countOfSwaped;
if(countOfSwaped < length)
index = ++startOfSwap;
}
}
return pStr;
}