第1章 面试的流程
第2章 面试需要的基础知识
第3章 高质量的代码
第4章 解决面试题的思路
第5章 优化时间和空间效率
第6章 面试中的各项能力
第7章 两个面试案例
面试题42:翻转单词顺序 VS 左旋转字符串
题目一:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",则输出"student. a am I"。
这个题目流传甚广,很多公司都多次拿来作面试题,很多应聘者也多次在各种博客或者书籍上看到过通过两次翻转字符串的解法,于是很快就可以跟面试官解释清楚解题思路:第一步翻转句子中所有的字符。比如翻转"I am a student. "中所有的字符得到".tneduts a ma I",此时不但翻转了句子中单词的顺序,连单词内的字符顺序也被翻转了。第二步再翻转每个单词中字符的顺序,就得到了"student. a am I"。这正是符合题目要求的输出。
这种思路的关键在于实现一个函数以翻转字符串中的一段。下面的函数Reverse可以完成这一功能:
接着我们可以用这个函数先翻转整个句子,再翻转句子中的每个单词。这种思路的参考代码如下:
在英语句子中,单词被空格符号分隔,因此我们可以通过扫描空格来确定每个单词的起始和终止位置。在上述代码的翻转每个单词阶段,指针pBegin指向单词的第一个字符,而pEnd指向单词的最后一个字符。
源代码:
本题完整的源代码详见42_1_ReverseWordsInSentence项目。
测试用例:
- 功能测试(句子中有多个单词,句子中只有一个单词)。
- 特殊输入测试(字符串指针为NULL指针、字符串的内容为空、字符串中只有空格)。
有经验的面试官看到一个应聘者几乎不假思索就能想出一种比较巧妙的算法,就会觉得他之前可能见过这个题目。这个时候很多面试官都会再问一个问题,以考查他是不是真的理解了这种算法。面试官一个常见的考查办法就是问一个类似的但更加难一点的问题。以这道题为例,如果面试官觉得应聘者之前看过这个思路,那他可能再问第二个问题:
题目二:字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果"cdefgab"。
要找到字符串旋转时每个字符移动的规律,不是一件轻易的事情。那我们是不是可以从解决第一个问题的思路中找到启发?在第一个问题中,如果输入的字符串之中只有两个单词,比如"hello world",那么翻转这个句子中的单词顺序就得到了"world hello"。比较这两个字符串,我们是不是可以把"world hello"看成是把原始字符串"hello world"的前面若干个字符转移到后面?也就是说这两个问题是非常相似的,我们同样可以通过翻转字符串的办法来解决第二个问题。
以"abcdefg"为例,我们可以把它分为两部分。由于想把它的前两个字符移到后面,我们就把前两个字符分到第一部分,把后面的所有字符都分到第二部分。我们先分别翻转这两部分,于是就得到"bagfedc"。接下来我们再翻转整个字符串,得到的"cdefgab"刚好就是把原始字符串左旋转2位的结果。
通过前面的分析,我们发现只需要调用3次前面的Reverse函数就可以实现字符串的左旋转功能。参考代码如下:
想清楚思路之后再写代码是一件很容易的事情,但我们也不能掉以轻心。面试官在检查与字符串相关的代码时经常会发现两种问题:一是输入空指针NULL时程序会崩溃;二是内存访问越界的问题,也就是试图访问不属于字符串的内存。例如如果输入的n小于0,指针pStr+n指向的内存就不属于字符串。如果我们不排除这种情况,试图访问不属于字符串的内存就会留下严重的内存越界的安全隐患。在前面的代码中,我们添加了两个if判断语句就是为了防止出现这两种问题。
源代码:
本题完整的源代码详见42_2_LeftRotateString项目。
测试用例:
- 功能测试(把长度为n的字符串左旋转0个字符、1个字符、2个字符、n-1个字符、n个字符、n+1个字符)。
- 特殊输入测试(字符串的指针为NULL指针)。
本题考点:
- 考查知识迁移的能力。当面试的时候遇到第二个问题,而之前我们做过翻转句子中单词的顺序这个题目,那如果能够把多次翻转字符串的思路迁移过来,就能很轻易地解决字符串左旋转的问题。
- 考查对字符串的编程能力。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论