程序员面试题精选100题(07)-翻转句子中单词的顺序
2012-02-04 12:02
477 查看
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。为简单起见,标 点符号和普通字母一样处理。
例如,输入"I am a student.",则输出"student. a am I"。
第一次遇到这道题是十一之前去一个公司笔试的时候,当时想到一个方法,似乎有点麻烦,只是在纸面上写了出来,并没有电脑上运行。后来去单位,跟几个同事讨论,得出了正确的思路,前段时间准备笔试的过程中在《程序 员面试宝典》中也见过,当时写出了全部代码的实现,并且运行正确,现在一个多月过去了,再次看到的时候该知道的方法依然记得,只是在编程的时候忽略了很多的细节,比如,如果想要在函数内部改变变量的值需要给函数传递的是引用, 数组的越界问题,如何确定互换顺序的中间元素,对于最后一个单词,应该检测的是他的结尾是不是字符串的结束符(我竟然将字符串的结束符写成'0',后来发现后才改为'\0'),有很多的问题听起来都很可笑,因为都是一些基础,但是我还是决定写出来,让自己印象深刻,对于曾经犯过的错误记录下来,过段时间再回过头来看的时候就可以避免相同的问题。
分析:
<方法一>:使用字符串。整体的一个思路就是先将整个字符串互换,然后再将相应的单词互换。即遍历全部互换的字 符串,记录起始点的位置,当遇到空格时即停止,此时再记录终止点的位置,互换起点和终点之间的单词即可,句子之中的 一些单词需要的是碰到' ',则停下开始颠倒单词,但是对于最后一个单词,需要判断遍历的数字值是否为'\0'。对于char 型,我们在对其赋值时需要在字符串的末尾加上一个'\0',表示字符串结束,对于string型,C++库函数已经封装好,会在初始化结束之后自动在末尾添加'\0',当我们使用string.length()函数时,获得的大小也是不包含'\0'的值,所以对颠倒后的字符串的遍历需要让循环变量i=string.length()的值,让他指到'\0'所在的位置,并以此来对最后一个单词的位置颠倒启动一定的判断作用。
在遍历的过程中有一些问题需要注意,基本上都是数组的下标的问题,一开始写的时候很多的一些关系没搞明白,必须不停的断点调试,总结出最后的结果,后来想了想他的原理,不需要举例子就可以相同了。例如,当互换整个句子和每一个单词时,只需要从第一个位置开始遍历到中间即可,在给定的条件中,我们知道的是整个句子的长度,因此只需要让循环变量i小于句子长度的一半即可,i<(length/2);因为length表示的是字符串的大小,所以i<(length/2);i所能到达的范围就是数组的前半部分,奇数时,i到达不了数组中间的元素(因为他也不需要颠倒),偶数时就正好是我们所需要的结果。
完整代码如下:
<方法二>:使用指针。主要也是为了能够当使用指针所指向的内容来改变字符串的值。在写代码的过程中依然有一些基础知识的问题困扰过我,主要是程序中不同作用范围的变量的存储问题,例如在一开始编程时写过这样一段代码:
这个程序在编译时就无法通过,主要是内存的访问问题,因为pChar是一个常量字符串,作用于全局范围,主要放置在静态变量,在程序的所有运行过程中是不变的。下面这段文字摘自《程序员面试宝典》中对于内存的一些讲解:
栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等。
堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。注意它与数据结构中的堆是两码事,分配方式倒是类似于链表。
全局区(静态区)(static):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在一块区域内,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
文字常量区:常量字符串就是放在这里的,程序结束后由系统释放。
程序代码区:存放函数体的二进制代码。
使用指针的代码如下:
例如,输入"I am a student.",则输出"student. a am I"。
第一次遇到这道题是十一之前去一个公司笔试的时候,当时想到一个方法,似乎有点麻烦,只是在纸面上写了出来,并没有电脑上运行。后来去单位,跟几个同事讨论,得出了正确的思路,前段时间准备笔试的过程中在《程序 员面试宝典》中也见过,当时写出了全部代码的实现,并且运行正确,现在一个多月过去了,再次看到的时候该知道的方法依然记得,只是在编程的时候忽略了很多的细节,比如,如果想要在函数内部改变变量的值需要给函数传递的是引用, 数组的越界问题,如何确定互换顺序的中间元素,对于最后一个单词,应该检测的是他的结尾是不是字符串的结束符(我竟然将字符串的结束符写成'0',后来发现后才改为'\0'),有很多的问题听起来都很可笑,因为都是一些基础,但是我还是决定写出来,让自己印象深刻,对于曾经犯过的错误记录下来,过段时间再回过头来看的时候就可以避免相同的问题。
分析:
<方法一>:使用字符串。整体的一个思路就是先将整个字符串互换,然后再将相应的单词互换。即遍历全部互换的字 符串,记录起始点的位置,当遇到空格时即停止,此时再记录终止点的位置,互换起点和终点之间的单词即可,句子之中的 一些单词需要的是碰到' ',则停下开始颠倒单词,但是对于最后一个单词,需要判断遍历的数字值是否为'\0'。对于char 型,我们在对其赋值时需要在字符串的末尾加上一个'\0',表示字符串结束,对于string型,C++库函数已经封装好,会在初始化结束之后自动在末尾添加'\0',当我们使用string.length()函数时,获得的大小也是不包含'\0'的值,所以对颠倒后的字符串的遍历需要让循环变量i=string.length()的值,让他指到'\0'所在的位置,并以此来对最后一个单词的位置颠倒启动一定的判断作用。
在遍历的过程中有一些问题需要注意,基本上都是数组的下标的问题,一开始写的时候很多的一些关系没搞明白,必须不停的断点调试,总结出最后的结果,后来想了想他的原理,不需要举例子就可以相同了。例如,当互换整个句子和每一个单词时,只需要从第一个位置开始遍历到中间即可,在给定的条件中,我们知道的是整个句子的长度,因此只需要让循环变量i小于句子长度的一半即可,i<(length/2);因为length表示的是字符串的大小,所以i<(length/2);i所能到达的范围就是数组的前半部分,奇数时,i到达不了数组中间的元素(因为他也不需要颠倒),偶数时就正好是我们所需要的结果。
完整代码如下:
<方法二>:使用指针。主要也是为了能够当使用指针所指向的内容来改变字符串的值。在写代码的过程中依然有一些基础知识的问题困扰过我,主要是程序中不同作用范围的变量的存储问题,例如在一开始编程时写过这样一段代码:
char *pChar = "today is saturday and tomorrow is sunday";
这个程序在编译时就无法通过,主要是内存的访问问题,因为pChar是一个常量字符串,作用于全局范围,主要放置在静态变量,在程序的所有运行过程中是不变的。下面这段文字摘自《程序员面试宝典》中对于内存的一些讲解:
栈区(stack):由编译器自动分配和释放,存放函数的参数值,局部变量的值等。
堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。注意它与数据结构中的堆是两码事,分配方式倒是类似于链表。
全局区(静态区)(static):全局变量和静态变量的存储是放在一起的,初始化的全局变量和静态变量在一块区域内,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
文字常量区:常量字符串就是放在这里的,程序结束后由系统释放。
程序代码区:存放函数体的二进制代码。
使用指针的代码如下:
#include <iostream> using namespace std; //使用两个指针,分别指向每一句话和每一个单词的开头,使用指针将指针所指内容进行互换进行互换 void Reverse(char *pB, char *pE) { //首先进行判断,函数输入的参数是否都为空,如果是,则不进行任何操作,直接返回。 if( pB == NULL || pE == NULL ) return; //如果pB<pE,则pB++,pE--,并互换他们的内容,主要用于更换整个句子的顺序以及每一个单词内字母的顺序 while(pB < pE ) { char temp = *pB; *pB = *pE; *pE = temp; pB++; pE--; } } char* ReversePerWords(char *pData) { //如果输入的参数为空,则不进行任何操作,返回NULL if(pData == NULL) return NULL; //初始化三个指针,将其指向初始字符串的开始位置 char *pBegin; char *pEnd ; pBegin = pEnd = pData; //开始进行逐单词的位置互换 while( 1 ) { //首先判断pEnd是否指向了一个空格位置或者字符串的结束符处,如果不是,则继续循环,是则循环终止 while( *pEnd != ' ' && *pEnd != '\0') pEnd++; //判断pEnd是否指向了字符串的结束符处 //如果是,则表明整个字符串只进行一次单词的互换,当互换结束后需要推出循环,并退出整个函数 //如果不是,则对单词内字母顺序互换之后还要处理pBegin和pEnd指针的位置。 if(*pEnd == '\0') { pEnd--; Reverse(pBegin , pEnd); break; } else { //先将pEnd指针指回到上一个不是空格的位置 pEnd--; Reverse(pBegin, pEnd); pEnd++; //该处判断主要用于连续空格处,以避免进行了多余的空格和空格的交换 //将pEnd指向下一个可以用于交换的地方,再将该地址赋予pBegin while( *pEnd == ' ') pEnd++; pBegin = pEnd; } } return pData; } void main() { char pChar[100] = "today is Saturday and tomorrow is Sunday?"; cout<<pChar <<endl; char *pStart = pChar; char *pEnd = pChar; pStart = pEnd = pChar; //先将pEnd指向整个句子的末尾 while( *pEnd != '\0') pEnd++; pEnd--; //更换整个句子的顺序 Reverse(pStart, pEnd); //错误提示:由于函数传递参数仅仅是值的传递,pStart和pEnd的值并没有改变,所以不需要对这两个变量进行更新,便可直接使用 //pStart = pEnd = pChar; //再互换整个句子中每个单词的顺序 ReversePerWords( pStart ); cout<<pChar<<endl; }
相关文章推荐
- 程序员面试题精选100题(07)-翻转句子中单词的顺序
- 程序员面试题精选100题(07)-翻转句子中单词的顺序
- 程序员面试题精选100题(07)-翻转句子中单词的顺序
- 程序员面试题精选100题(07)-翻转句子中单词的顺序[算法]
- 程序员面试题精选100题(07)-翻转句子中单词的顺序
- 程序员面试题精选(07)-翻转句子中单词的顺序
- 程序员面试题精选100题(07)-翻转句子中单词的顺序
- 程序员面试题精选100题(07)-翻转句子中单词的顺序[算法]
- 程序员面试题精选100题(07)-翻转句子中单词的顺序[算法]
- 程序员面试题精选-翻转句子中单词的顺序
- 程序员面试100题(算法)之翻转句子中单词的顺序
- 程序员面试题100题第07题——翻转句子中单词的顺序
- 程序员面试题精选(7):翻转句子中单词的顺序
- 【程序员面试题】翻转句子中单词的顺序
- 程序员面试50题(3)—翻转句子中单词的顺序[算法]
- IT公司100题-10-翻转句子中单词的顺序
- 程序员面试题精选-翻转句子中单词的顺序[算法]
- 面试100题:10.翻转句子中单词的顺序
- 面试100题:10.翻转句子中单词的顺序
- 翻转句子中单词的顺序 【微软面试100题 第十题】