摘要: 题目:两个单向链表,找出它们的第一个公共结点。链表的结点定义为:struct ListNode{ int m_nKey; ListNode* m_pNext;};分析:这是一道微软的面试题。微软非常喜欢与链表相关的题目,因此在微软的面试题中,链表出现的概率相当高。如果两个单向链表有公共的结点,也就是说两个链表从某一结点开始,它们的m_pNext都指向同一个结点。但由于是单向链表的结点,每个结点只有一个m_pNext,因此从第一个公共结点开始,之后它们所有结点都是重合的,不可能再出现分叉。所以,两个有公共结点而部分重合的链表,拓扑形状看起来像一个Y,而不可... 阅读全文
posted @ 2012-08-06 17:03 wolenski 阅读(182) 评论(0) 推荐(0)
摘要: 题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。分析:这是一道很新颖的关于位运算的面试题。首先我们考虑这个问题的一个简单版本:一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。这个题目的突破口在哪里?题目为什么要强调有一个数字出现一次,其他的出现两次?我们想到了异或运算的性质:任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现依次的数字,因为那些出现两次的数字全部在异或中抵消掉了。有了上面简单问题 阅读全文
posted @ 2012-08-06 16:41 wolenski 阅读(242) 评论(0) 推荐(0)
摘要: 题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:struct ListNode{ int m_nKey; ListNode* m_pNext;};函数的声明如下:void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);分析:这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,更重要的是,还能考察我们对时间复杂度的理解。在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺... 阅读全文
posted @ 2012-08-06 16:29 wolenski 阅读(176) 评论(0) 推荐(0)
摘要: 题目:用C++设计一个不能被继承的类。分析:这是Adobe公司2007年校园招聘的最新笔试题。这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是一道很好的题目。在Java中定义了关键字final,被final修饰的类不能被继承。但在C++中没有final这个关键字,要实现这个要求还是需要花费一些精力。首先想到的是在C++中,子类的构造函数会自动调用父类的构造函数。同样,子类的析构函数也会自动调用父类的析构函数。要想一个类不能被继承,我们只要把它的构造函数和析构函数都定义为私有函数。那么当一个类试图从它那继承的时候,必然会由于试图调用构造函数、析构函数而导致编译错误。可是这个类的构造函 阅读全文
posted @ 2012-08-06 15:58 wolenski 阅读(1022) 评论(0) 推荐(0)
摘要: 题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:struct ListNode{ int m_nKey; ListNode* m_pNext;};分析:这是一道很有意思的面试题。该题以及它的变体经常出现在各大公司的面试、笔试题中。看到这道题后,第一反应是从头到尾输出比较简单。于是很自然地想到把链表中链接结点的指针反转过来,改变链表的方向。然后就可以从头到尾输出了。反转链表的算法详见本人面试题精选系列的第19题,在此不再细述。但该方法需要额外的操作,应该还有更好的方法。接下来的想法是从头到尾遍历链表,每经过一个结点的时候,把该结点放到... 阅读全文
posted @ 2012-08-06 15:24 wolenski 阅读(211) 评论(0) 推荐(0)
摘要: 问题:给出如下CMyString的声明,要求为该类型添加赋值运算符函数。class CMyString{public: CMyString(char* pData = NULL); CMyString(const CMyString& str); ~CMyString(void); private: char* m_pData;};当面试官要求应聘者定义一个复制运算符函数时,他会关注如下几点:·是否把返回值的类型声明为该类型的引用,并在函数结束前返回实例自身(即*this)的引用?只有返回一个引用,才可以允许连续赋值。否则如果函数的返回值是void,假设有三个... 阅读全文
posted @ 2012-08-06 15:19 wolenski 阅读(480) 评论(0) 推荐(0)
摘要: 题目:输入一个整数数组,调整数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。要求时间复杂度为O(n)。分析:如果不考虑时间复杂度,最简单的思路应该是从头扫描这个数组,每碰到一个偶数时,拿出这个数字,并把位于这个数字后面的所有数字往前挪动一位。挪完之后在数组的末尾有一个空位,这时把该偶数放入这个空位。由于碰到一个偶数,需要移动O(n)个数字,因此总的时间复杂度是O(n2)。要求的是把奇数放在数组的前半部分,偶数放在数组的后半部分,因此所有的奇数应该位于偶数的前面。也就是说我们在扫描这个数组的时候,如果发现有偶数出现在奇数的前面,我们可以交换他们的顺序,交换之后就符合 阅读全文
posted @ 2012-08-06 10:48 wolenski 阅读(249) 评论(0) 推荐(0)
摘要: 题目:输入一棵二元树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。例如:输入二元树:10/\6 14/ / \41216输出该树的深度3。二元树的结点定义如下:struct SBinaryTreeNode // a node of the binary tree{ int m_nValue; // value of node SBinaryTreeNode *m_pLeft; // left child of node SBinaryTreeNode *m_pRi... 阅读全文
posted @ 2012-08-06 10:37 wolenski 阅读(215) 评论(0) 推荐(0)
摘要: 题目:输入一个正数n,输出所有和为n连续正数序列。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以输出3个连续序列1-5、4-6和7-8。分析:这是网易的一道面试题。这道题和本面试题系列的第10题有些类似。我们用两个数small和big分别表示序列的最小值和最大值。首先把small初始化为1,big初始化为2。如果从small到big的序列的和大于n的话,我们向右移动small,相当于从序列中去掉较小的数字。如果从small到big的序列的和小于n的话,我们向右移动big,相当于向序列中添加big的下一个数字。一直到small等于(1+n)/2,因为序列至少要有两个数字。基 阅读全文
posted @ 2012-08-06 10:31 wolenski 阅读(852) 评论(0) 推荐(0)