51.和为n连续正数序列。
题目:输入一个正数n,输出所有和为n连续正数序列。
分析:这是网易的一道面试题。
52.二元树的深度。
题目:输入一棵二元树的根结点,求该树的深度。
从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
例如:输入二元树:
10
/ \
6 14
/ / \
4 12 16
输出该树的深度3。
二元树的结点定义如下:
struct SBinaryTreeNode // a node of the binary tree
{
int m_nValue; // value of node
SBinaryTreeNode *m_pLeft; // left child of node
SBinaryTreeNode *m_pRight; // right child of node
};
分析:这道题本质上还是考查二元树的遍历。
53.字符串的排列。
题目:输入一个字符串,打印出该字符串中字符的所有排列。
例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串
abc、acb、bac、bca、cab和cba。
因此在过去一年中频繁出现在各大公司的面试、笔试题中。
54.调整数组顺序使奇数位于偶数前面。
所有偶数位于数组的后半部分。要求时间复杂度为O(n)。
55.
题目:类CMyString的声明如下:
class CMyString
{
public:
CMyString(char* pData = NULL);
CMyString(const CMyString& str);
~CMyString(void);
CMyString& operator = (const CMyString& str);
char* m_pData;
};
请实现其赋值运算符的重载函数,要求异常安全,即当对一个对象进行赋值时发生异常,对象的状态不能改变
56.最长公共字串。
题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,
则字符串一称之为字符串二的子串。
注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。
请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,
则输出它们的长度4,并打印任意一个子串。
分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,
我们可以把该问题定义如下:
给出两个字符串S和T,S的长度为m,T的长度为n,找出S与T的最长公共子串。
假设S = “ABAB”,T=“BABA”,我们可以构造一个如下的矩阵:
A | B | A | B | ||
0 | 0 | 0 | 0 | 0 | |
B | 0 | 0 | 1 | 0 | 1 |
A | 0 | 1 | 0 | 2 | 0 |
B | 0 | 0 | 2 | 0 | 3 |
A | 0 | 1 | 0 | 3 | 0 |
对于数组array[m][n],扩展为array[m+1][n+1],这样是为了方便初始化,减少循环中对边界的判断。
- if( S[i] == T[j] ) array[i+1][j+1] = array[i][j] + 1
- if( S[i] != T[j] ) array[i+1][j+1] = 0
1 #include <string.h> 2 #include <stdlib.h> 3 #include <stdio.h> 4 5 const char * LongestCommonSubstring(const char * strA, const char * strB) 6 { 7 char * LCS = NULL; 8 const size_t LengthA = strlen(strA); 9 const size_t LengthB = strlen(strB); 10 size_t LCSLength = 0; 11 unsigned int PositionX = 0; 12 unsigned int PositionY = 0; 13 14 int i, j; 15 int Matrix[LengthA + 1][LengthB + 1];; 16 17 for(i = 0; i < LengthA ; ++i) 18 { 19 for(j = 0; j < LengthB ; ++j) 20 { 21 Matrix[i][j] = 0; 22 } 23 } 24 25 for(i = 0; i < LengthA; ++i) 26 { 27 for(j = 0; j < LengthB; ++j) 28 { 29 if(strA[i] == strB[j]) 30 { 31 if((i == 0)||(j == 0)) 32 Matrix[i][j] = 1; 33 else 34 Matrix[i][j] = Matrix[i - 1][j - 1] + 1; 35 } 36 if(Matrix[i][j] > LCSLength) 37 { 38 LCSLength = Matrix[i][j]; 39 PositionX = i; 40 PositionY = j; 41 } 42 } 43 } 44 45 46 LCS = (char *)malloc(LCSLength + 1); 47 int index = LCSLength - 1; 48 while(index >= 0) 49 { 50 LCS[index] = strA[PositionX]; 51 --index; 52 --PositionX; 53 } 54 LCS[LCSLength] = '\0'; 55 56 return LCS; 57 } 58 int main(int argc, char **argv) 59 { 60 const char * strA = "abab"; 61 const char * strB = "baba"; 62 const char * LCS = LongestCommonSubstring(strA, strB); 63 printf("Longest Common Substring is %s\n", LCS); 64 return 0; 65 }
题目:某队列的声明如下: template<typename T> class CQueue
{
public:
CQueue() {}
~CQueue() {} void appendTail(const T& node); // append a element to tail
void deleteHead(); // remove a element from head private:
T> m_stack1;
T> m_stack2;
}; 分析:从上面的类的声明中,我们发现在队列中有两个栈。
因此这道题实质上是要求我们用两个栈来实现一个队列。
相信大家对栈和队列的基本性质都非常了解了:栈是一种后入先出的数据容器,
因此对队列进行的插入和删除操作都是在栈顶上进行;队列是一种先入先出的数据容器,
我们总是把新元素插入到队列的尾部,而从队列的头部删除元素。
58.从尾到头输出链表。
题目:输入一个链表的头结点,从尾到头反过来输出每个结点的值。链表结点定义如下:
struct ListNode
{
ListNode* m_pNext;
};
分析:这是一道很有意思的面试题。
该题以及它的变体经常出现在各大公司的面试、笔试题中。
方法二、设一个栈,从头到尾遍历一次,把结点值压力栈中,再出栈打印。
方法三、递归。
59.不能被继承的类。
题目:用C++设计一个不能被继承的类。
这道题除了考察应聘者的C++基本功底外,还能考察反应能力,是一道很好的题目。
60.在O(1)时间内删除链表结点。
题目:给定链表的头指针和一个结点指针,在O(1)时间删除该结点。链表结点的定义如下:
struct ListNode
{
int m_nKey;
ListNode* m_pNext;
};
函数的声明如下:
void DeleteNode(ListNode* pListHead, ListNode* pToBeDeleted);
分析:这是一道广为流传的Google面试题,能有效考察我们的编程基本功,还能考察我们的反应速度,
解答:
在链表中删除一个结点,最常规的做法是从链表的头结点开始,顺序查找要删除的结点,找到之后再删除。由于需要顺序查找,时间复杂度自然就是O(n) 了。
我们之所以需要从头结点开始查找要删除的结点,是因为我们需要得到要删除的结点的前面一个结点。我们试着换一种思路。我们可以从给定的结点得到它的下一个结点。这个时候我们实际删除的是它的下一个结点,由于我们已经得到实际删除的结点的前面一个结点,因此完全是可以实现的。当然,在删除之前,我们需要需要把给定的结点的下一个结点的数据拷贝到给定的结点中。此时,时间复杂度为O(1)。
using namespace std;
typedef struct LNode{
int data;
LNode *next;
}LNode, *List;
void InsertList(List &l, int data)//头插入节点
{
List head;
LNode *p=new LNode;
p->data=data;
if(NULL==l)
p->next=NULL;
else
p->next=l;
l=p;
}
void PrintList(List l)//打印链表
{
LNode *p=l;
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
}
void DeleteNode(List &l, LNode *toBeDeleted)//删除链表l中的toBeDeleted节点
{
LNode *p;
if(!l || !toBeDeleted)
return;
if(l==toBeDeleted)//若删除的节点时表头
{
p=l->next;
delete toBeDeleted ;
l=p;
}
else
{
if(toBeDeleted->next==NULL)//若删除的节点时最后一个节点
{
p=l;
while(p->next!=toBeDeleted)
p=p->next;
p->next=NULL;
delete toBeDeleted;
}
else//删除节点时中间节点
{
p=toBeDeleted->next;
toBeDeleted->data=p->data;
toBeDeleted->next=p->next;
delete p;
}
}
}
void main()
{
List l=NULL;
LNode *p;
int n;
InsertList(l, 3);
InsertList(l, 7);
InsertList(l, 12);