剑指offer--7题
*题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。
*句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
*例如输入“I am a student.”,则输出“student. a am I”。
终于有一道题的思路是一样的了! 感觉自己的基础太差了!
思路:整体反转+单词再反转。
//时间复杂度为O(n) //自己编写 #include "stdafx.h" #include<iostream> void ReserveSentence(char str[]); using namespace std; int main(int argc, char* argv[]) { char str[] = "Hello! Ms. World!"; ReserveSentence(str); return 0; } void ReserveSentence(char str[]) { int len = strlen(str); int i,j; for(i=0,j=len-1; j>i; i++,j--) { char temp = str[i]; str[i] = str[j]; str[j] = temp; } char* kptr,*iptr; char ytemp; char* temptr; kptr = iptr = str; bool ReachEnd = false; while(*iptr != '\0' && !ReachEnd) { while(*iptr != ' ' && *iptr != '\0') iptr++; if(*iptr == '\0') ReachEnd = true; temptr = iptr+1; iptr--; while(iptr > kptr) { ytemp = *iptr; *iptr = *kptr; *kptr = ytemp; iptr--; kptr++; } kptr = iptr = temptr; } cout<<str<<endl; } //标准答案 /*////////////////////////////////////////////////////////////////////// // Reverse a string between two pointers // Input: pBegin - the begin pointer in a string // pEnd - the end pointer in a string /////////////////////////////////////////////////////////////////////// void Reverse(char *pBegin, char *pEnd) { if(pBegin == NULL || pEnd == NULL) return; while(pBegin < pEnd) { char temp = *pBegin; *pBegin = *pEnd; *pEnd = temp; pBegin ++, pEnd --; } } /////////////////////////////////////////////////////////////////////// // Reverse the word order in a sentence, but maintain the character // order inside a word // Input: pData - the sentence to be reversed /////////////////////////////////////////////////////////////////////// char* ReverseSentence(char *pData) { if(pData == NULL) return NULL; char *pBegin = pData; char *pEnd = pData; while(*pEnd != '\0') pEnd ++; pEnd--; // Reverse the whole sentence Reverse(pBegin, pEnd); // Reverse every word in the sentence pBegin = pEnd = pData; while(*pBegin != '\0') { if(*pBegin == ' ') { pBegin ++; pEnd ++; continue; } // A word is between with pBegin and pEnd, reverse it else if(*pEnd == ' ' || *pEnd == '\0') { Reverse(pBegin, --pEnd); pBegin = ++pEnd; } else { pEnd ++; } } return pData; }*/
由该题+博主程序+相关评论,自己也学到不少东西(我发现看评论也很费劲啊,参差不齐,估计像我这样的fish不少吧)。
首先,与博主的程序相比,自己所写并未考虑到单词与单词之间或者句子开头有可能是空格的情况,区别点如下:
if(*pBegin == ' ') { pBegin ++; pEnd ++; continue; }
其次,有很多问题得到解决,在这里总结下,帮助记忆和回顾
1、就ReverseSentence(char *pData)而言,其输入参数为char*类型,这本身就要求了pData所指向的字符串可被修改;如果为const char*,则pData所指向的字符串只能读,而不能被修改。所以,自己在之前所遇到的“can't convert const char[] to char*”,就是指只能被读的字符串不能转换为既能被读又能被写的字符串。
针对评论:
如果是这样使用,程序正常 char pSentence[] = "I am a student."; char *p = ReverseSentence(pSentence); 但如果是这样: char *pSentence = "I am a student."; char *p = ReverseSentence(pSentence); 程序会在*pBegin = *pEnd; 处异常, 应该是由于这种情况下pSentence指向的是常量字符串,编译器不允许对常量字符串修改的缘故。 楼主代码还不够健壮 ;-)
及回复:
这个函数的作用就是翻转一个句子,会修改字符串的内容。调用者传入常量字符串,本身不符合这个函数的语义。不过从设计API的角度,的确不过健壮。请问哪位有好的解决方案吗? API设计的角度,你使用char*就是要求调用者给出的字符串可修改。 楼上的写法 char* p = "const string"; 本身就是不合规范的,新的编译器都会给严重的警告。
char pSentence[] = "I am a student."; 将常量字符串"I am a student."(位于静态存储区)复制到堆栈中,并将复制后的字符串的地址赋予pSentence,所以char pSentence[] = "I am a student.";所造成的结果:当调用ReverseSentence(pSentence)时,pSentence为char*类型,成功!
char *pSentence = "I am a student."; 将常量字符串"I am a student."(位于静态存储区)的地址赋给pSentence,为常量指针(其实应当声明为
const char *pSentence = "I am a student.";),所以当调用ReverseSentence(pSentence)时,会报错!
2、函数调用的问题(基本问题,看来自己基础不太扎实)
博主 你好 Reverse函数中的pBegin 和pEnd 在翻转完一个单词后分别指向的是单词中间的位置,并不是一开始的头和尾。那 else if(*pEnd == ' ' || *pEnd == '\0') { Reverse(pBegin, --pEnd); pBegin = ++pEnd; } 这里执行完的话两个指针的位置还是在一个单词内部吧?没有起到指向单词后面的空格的效果?不知是不是我理解错误了。
其实是在该函数被调用时,按值传递!!!所以原pEnd和pBegin不变!
3、当使用指针时,先判空:
1、函数无返回值时,则如下:
if(pBegin == NULL || pEnd == NULL) return;
2、函数返回char*时,则如下:
if(pData == NULL) return NULL;
清醒时做事,糊涂时读书,大怒时睡觉,独处时思考; 做一个幸福的人,读书,旅行,努力工作,关心身体和心情,成为最好的自己
-- 共勉