剑指offer--21题
#include "stdafx.h"
#include<iostream>
using namespace std;
void LeftRotateString(char* str,int n);
void StringReverse(char* pStart, char* pEnd);
int main(int argc, char* argv[])
{
char str[]="abcdef"; //将"abcdef"拷贝到str[]中,str指向拷贝字符串的首址
int n=3;
LeftRotateString(str,n);
return 0;
}
/*void LeftRoundOper(char* str,int n)
{
int len=strlen(str);
char strtemp[100];
if(n<0 || n>len)
strtemp[0]='\0';
int i,j=0;
for(i=n; i<len; i++)
{
strtemp[j++]=str[i];
}
for(i=0; i<n; i++)
{
strtemp[j++]=str[i];
}
strtemp[j]='\0';
for(i=0; i<j; i++)
cout<<strtemp[i]<<' ';
cout<<endl;
}*/
/*接下来的一种思路可能要稍微麻烦一点。我们假设把字符串左旋转m位。
于是我们先把第0个字符保存起来,把第m个字符放到第0个的位置,在把第2m个字符放到第m个的位置…依次类推,
一直移动到最后一个可以移动字符,最后在把原来的第0个字符放到刚才移动的位置上。
接着把第1个字符保存起来,把第m+1个元素移动到第1个位置…重复前面处理第0个字符的步骤,
直到处理完前面的m个字符。*/
/*我们还是把字符串看成有两段组成的,记位XY。左旋转相当于要把字符串XY变成YX。
我们先在字符串上定义一种翻转的操作,就是翻转字符串中字符的先后顺序。把X翻转后记为XT。显然有(XT)T=X。
我们首先对X和Y两段分别进行翻转操作,这样就能得到XTYT。接着再对XTYT进行翻转操作,得到(XTYT)T=(YT)T(XT)T=YX。
正好是我们期待的结果。
分析到这里我们再回到原来的题目。
我们要做的仅仅是把字符串分成两段,第一段为前面m个字符,其余的字符分到第二段。
再定义一个翻转字符串的函数,按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。*/
void LeftRotateString(char* str,int n)
{
if(str!=NULL)
{
int len = strlen(str);
if(len>0 && n>0 && n<len)
{
StringReverse(str,str+n);
StringReverse(str+n,str+len);
StringReverse(str,str+len);
cout<<str<<endl;
}
}
}
void StringReverse(char* pStart, char* pEnd)
{
if(pStart!=NULL && pEnd!=NULL)
{
pEnd--;
while(pStart<pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pEnd--;
pStart++;
}
}
}
/*标准答案
#include "string.h"
///////////////////////////////////////////////////////////////////////
// Move the first n chars in a string to its end
///////////////////////////////////////////////////////////////////////
char* LeftRotateString(char* pStr, unsigned 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;
// reverse the first part of the string
ReverseString(pFirstStart, pFirstEnd);
// reverse the second part of the strint
ReverseString(pSecondStart, pSecondEnd);
// reverse the whole string
ReverseString(pFirstStart, pSecondEnd);
}
}
return pStr;
}
///////////////////////////////////////////////////////////////////////
// Reverse the string between pStart and pEnd
///////////////////////////////////////////////////////////////////////
void ReverseString(char* pStart, char* pEnd)
{
if(pStart != NULL && pEnd != NULL)
{
while(pStart <= pEnd)
{
char temp = *pStart;
*pStart = *pEnd;
*pEnd = temp;
pStart ++;
pEnd --;
}
}
}
*/
给自己做个备份,记录点点滴滴,看进步如何。。。
在验证各种方法时,遇到运行问题,也就是自己之前经常碰到的:在使用指针时,经常出现内存问题
比如该题中,
int main(int argc, char* argv[])
{
char str[]="abcdef";
int n=3;
LeftRotateString(str,n);
return 0;
}
第一种方法,使用char str[]="abcdef";和char* str="abcdef";均可
但标准答案只能使用char str[]="abcdef";
为什么?原因很简单,可惜我才明白。。
参考:http://bbs.csdn.net/topics/340111697
字符串“hello world”本身就是一个字符串常量指针,存储在静态存储区,而第一个指针p,无非就是一个地址的拷贝,也就是“hello world”地址的拷贝,此时的p指向静态存储区的"hello world"
实际就相当于 const char *p = "hello world";
======================================================================================
而对于p[]来说就不一样了,虽然"hello world"本身是常量,不过此时拷贝给p[]的不是地址,而是内容,也就是 “hello world”,也就是p本身拥有一个自己的hello world副本,而p此时代表的是自己副本的内存地址,而非静态区的"hello world"。由于p[]是一个局部变量,它的生存期只有在局部函数中,一旦结束调用,p就会消亡,p的内容就会被覆盖!因此结果是不确定的!
所以,"abcdef"是字符串常量,存储于静态存储区,直到程序结束才释放。
char* str="abcdef"将该静态存储区的地址赋予str,所以*str,str[i]均是取原字符串常量中的字符,切记:只能‘读’,不能‘写’,也就是不能修改值!
char str[]="abcdef"则将"abcdef"拷贝到动态存储区(栈)中,使之成为局部变量,此时的str将指向局部存储区的首址,*str,str[i]均取拷贝字符串的各值。因此能‘读’能‘写’。
进一步分析:自己所写的程序(最简单的),仅涉及到str[i],并开辟另外的存储空间,所以char* str="abcdef"与char str[]="abcdef"均可;
标准答案中涉及反转,也就是涉及到本地交换,所以只能char str[]="abcdef",不能修改原字符串常量。