C++面试题
2015-08-16 17:37
591 查看
1. 一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。求总共有多少总跳法?
2. 求子数组的最大和
3. 将二元查找树变成排序的双向链表
4. 找出数组中唯一出现2次的数
5. 输入一个数,判断它是不是回文数
6. 编写一个程序,计算一个字符串中子串出现的次数
7. 求1~1000之间的完全数
8. 求1+2+…+n
9. 输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
/**************************************************************
题目:输入一个已经按升序排序过的数组和一个数字, 在数组中查找两个数,
使得它们的和正好是输入的那个数字。 要求时间复杂度是O(n)。如果有多对
数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
**************************************************************/
#include <iostream>
using namespace std;
void find(int R[],int n,int sum);
int main()
{
int arr[6] = {1,2,4,7,11,15};
int sum = 15;
find(arr,6,sum);
return 0;
}
void find(int R[],int n,int sum)
{
int i=0;
int j=n-1;
while(i < j)
{
if(R[i]+R[j] == sum)
{
cout<<sum<<" = "<<R[i]<<" + "<<R[j]<<endl;
return;
}
R[i]+R[j]<sum ? ++i : --j;
}
cout<<"Cannot find!"<<endl;
}
10. 约瑟夫环
/****************************************************************************
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字
(第一个为当前数字本身,第二个为当前数字的下一个数字)。当一个数字删除后,从被删除
数字的下一个继续删除第m个数字。求出在这个圆圈中剩下的最后一个数字。
分析:既然题目有一个数字圆圈,很自然的想法是我们用一个数据结构来模拟这个圆圈。
在常用的数据结构中,我们很容易想到用环形列表。我们可以创建一个总共有m个数字的环形列表,
然后每次从这个列表中删除第m个元素。 我们用STL中std::list来模拟这个环形列表。
由于list并不是一个环形的结构,因此每次跌代器扫描到列表末尾的时候,
要记得把跌代器移到列表的头部。这样就是按照一个圆圈的顺序来遍历这个列表了。
这种思路需要一个有n个结点的环形列表来模拟这个删除的过程,因此内存开销为O(n)。
而且这种方法每删除一个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn)。
****************************************************************************/
#include <iostream>
using namespace std;
#include <list>
int getLastNumber(list<int> numList,unsigned m);
int main()
{
list<int> numList;
unsigned n;
unsigned m;
cout<<"请输入n:";
cin>>n;
cout<<"请输入m:";
cin>>m;
if(n<1 || m<1)
{
cout<<"\n输入有误!\n"<<endl;
return -1;
}
for(unsigned i=0;i<n;++i)
numList.push_back(i);
cout<<"Last Number: "<<getLastNumber(numList,m)<<endl;
return 0;
}
int getLastNumber(list<int> numList, unsigned m)
{
list<int>::iterator currentIter = numList.begin();
list<int>::iterator nextIter;
while(numList.size() > 1)
{
for(unsigned i=1;i<m;++i)
{
++currentIter;
if(currentIter == numList.end())
currentIter = numList.begin();
}
// 找到第m个数,将其从list中移出
nextIter = ++currentIter;
if(nextIter == numList.end())
nextIter = numList.begin();
--currentIter;
numList.erase(currentIter);
currentIter = nextIter;
}
return *(currentIter);
}
/*********************************************************************** 题目:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。 求总共有多少总跳法。 分析:首先我们考虑最简单的情况。如果只有1级台阶,那显然只有一种跳法。 如果有2级台阶,那就有两种跳的方法了:一种是分两次跳,每次跳1级; 另外一种就是一次跳2级。 现在我们再来讨论一般情况。我们把n级台阶时的跳法看成是n的函数,记为f(n)。 当 n=1 时有 1 种跳法;当 n=2 时有 2 种跳法; 当n>2时,第一次跳的时候就有两种不同的选择: 一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目, 即为f(n-1);另外一种选择是第一次跳2级,此时跳法数目等于后面剩下的n-2级 台阶的跳法数目,即为f(n-2)。 因此n级台阶时的不同跳法的总数f(n)=f(n-1)+ f(n-2)。 ***********************************************************************/ #include <iostream> using namespace std; int f(int n) { if(n < 1) { cout<<"台阶数至少为1!"<<endl; return -1; } if(1 == n) return 1; if(2 == n) return 2; return f(n-1) + f(n-2); } int main() { int num; cout<<"请输入台阶数: "; cin>>num; cout<<"共有 "<<f(num)<<" 种跳法."<<endl; return 0; }
2. 求子数组的最大和
/************************************************************************ 题目: 输入一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 求所有子数组的和的最大值。要求时间复杂度为O(n)。 例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5, 和最大的子数组为3, 10, -4, 7, 2, 因此输出为该子数组的和18。 ************************************************************************/ #include <iostream> using namespace std; int getMaxSubArraySum(int R[],int n); int main() { int arr[8] = {1,-2,3,10,-4,7,2,-5}; int maxSubSum = getMaxSubArraySum(arr,8); cout<<maxSubSum<<endl; return 0; } int getMaxSubArraySum(int R[],int n) { int maxSumValue = 0;//结果 int subArraySumValue = 0;//累加和 int max = R[0];//保存数组中的最大值 for(int i=0;i<n;++i) { subArraySumValue += R[i]; if(subArraySumValue < 0) { subArraySumValue = 0; } if(subArraySumValue > maxSumValue) { maxSumValue = subArraySumValue; } if(max < R[i]) { max = R[i]; } } if(max < 0) { //若数组中所有的数都为负数,则返回最大的一个数 return max; } return maxSumValue; }
3. 将二元查找树变成排序的双向链表
/********************************************************** 题目: 输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。 要求: 不能创建任何新的结点,只能调整指针的指向。 **********************************************************/
/********************************************************** 思路: 1.构造二叉查找树; 2.中序遍历二叉查找树; 3.将访问到的结点调整为双向链表。 **********************************************************/ //测试程序 #include <iostream> using namespace std; //定义二元查找树结点的数据结构 struct BSTreeNode { int m_value; BSTreeNode *m_pLeft; BSTreeNode *m_pRight; }; BSTreeNode *pHead = NULL; BSTreeNode *pIndex = NULL;//指向前一个结点 //建立二叉排序树 void addBSTreeNode(BSTreeNode *&pCurrent, int val); //中序遍历,同时调整结点指针 void inOrderBSTreeNode(BSTreeNode *pNode); //调整结点指针 void convert2DoubleLinkedList(BSTreeNode *pCurrent); int main() { BSTreeNode *pRoot = NULL; addBSTreeNode(pRoot,10); addBSTreeNode(pRoot,6); addBSTreeNode(pRoot,14); addBSTreeNode(pRoot,4); addBSTreeNode(pRoot,8); addBSTreeNode(pRoot,12); addBSTreeNode(pRoot,16); inOrderBSTreeNode(pRoot); return 0; } void addBSTreeNode(BSTreeNode *&pCurrent, int val) { if(NULL == pCurrent) { BSTreeNode *pNode = new BSTreeNode(); pNode->m_value = val; pNode->m_pLeft = NULL; pNode->m_pRight = NULL; pCurrent = pNode; } else { if(pCurrent->m_value < val) { addBSTreeNode(pCurrent->m_pRight,val); } else if(pCurrent->m_value > val) { addBSTreeNode(pCurrent->m_pLeft,val); } else { cout<<"Node repeated!!!"<<endl; } } } void inOrderBSTreeNode(BSTreeNode *pNode) { if(NULL == pNode) { return; } if(NULL != pNode->m_pLeft) { inOrderBSTreeNode(pNode->m_pLeft); } convert2DoubleLinkedList(pNode); if(NULL != pNode->m_pRight) { inOrderBSTreeNode(pNode->m_pRight); } } void convert2DoubleLinkedList(BSTreeNode *pCurrent) { //使当前结点的左指针指向双向链表中的最后一个结点 pCurrent->m_pLeft = pIndex; if(NULL == pIndex)//双向链表尚未建立 { pHead = pCurrent; } else { pIndex->m_pRight = pCurrent; } pIndex = pCurrent; cout<<pCurrent->m_value<<" "; }
4. 找出数组中唯一出现2次的数
/*********************************************************************** 题目: 假设你有一个用1001个整数组成的数组,这些整数是任意排列的, 但是你知道所有的整数都在1到1000(包括1000)之间。 此外,除一个数字出现两次外,其他所有数字只出现一次。 假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。 如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗? ***********************************************************************/ /*********************************************************************** 思路: (1001个数异或结果)与(1-1000异或的结果)再做异或,即可。 原理: 设重复数为A, 其余999个数异或结果为B。 1001个数异或结果为A^A^B, 1-1000异或结果为A^B。 由于异或满足交换律和结合律, 且X^X = 0, 0^X = X; 则有(A^B)^(A^A^B)=A^B^B=A ***********************************************************************/ //测试程序 #include <iostream> using namespace std; void showRepeated(int R[],int n); int main() { int a[] = {5,2,4,3,4,1,6}; showRepeated(a,6); return 0; } void showRepeated(int R[],int n) { int result = 0; for(int i=0;i<=n;++i) { result ^= R[i]; } for(int i=1;i<=n;++i) { result ^= i; } cout<<"result = "<<result<<endl; }
5. 输入一个数,判断它是不是回文数
//输入一个数,判断它是不是回文数。 #include <iostream> using namespace std; bool isPalindromicNumber(int x); int main() { int x = 0; cout<<"Please input a number:"; cin>>x; if(isPalindromicNumber(x)) cout<<x<<"是回文数."<<endl; else cout<<x<<"不是回文数."<<endl; return 0; } bool isPalindromicNumber(int x) { int y = 0; int result = 0; int temp = x; while(x!=0){ y = x%10; x /= 10; result = result*10+y; } if(result==temp) return true; else return false; }
6. 编写一个程序,计算一个字符串中子串出现的次数
#include <stdio.h> #include <string.h> int getCount(char* str,char* substr) { int i=0,j=0,count=0; while(*(str+i)){ if(*(str+i)==*(substr+j)){ i++; j++; } else{ if(j==0) i++; else j = 0; } if(j==strlen(substr)){ count++; j = 0; } } return count; } int main() { char* str = "HHiHelloHHioHhiHrlHIodHioplloHHii"; char* substr = "Hi"; int count = getCount(str,substr); printf("子串出现的次数:%d\n",count); return 0; }
7. 求1~1000之间的完全数
//如果一个数恰好等于它的真因子之和,则称该数为“完全数”。 //根据完全数的定义,先计算所选取的整数num的真因子,将各因子累加于sum,若sum等于num,则num为完全数。 #include <iostream> using namespace std; bool isWanQuanShu(int num);//判断num是否为完全数 int main(){ for(int i=2;i<1000;i++){ if(isWanQuanShu(i)){ cout<<i<<" "; } } cout<<endl; return 0; } bool isWanQuanShu(int num){ int sum = 0; for(int i=1;i<=num/2;i++) if(num%i == 0) sum += i; if(sum == num) return true; else return false; }
8. 求1+2+…+n
/********************************************************** 题目: 求1+2+…+n 要求: 不能使用乘除法、for、while、if、else、switch、case 等关键字以及条件判断语句(A?B:C) **********************************************************/ /********************************************************** 思路: 定义一个类,我们new一个含有n个这种类型元素的数组,那么该类 的构造函数将会被调用n次。可以将需要执行的代码放到构造函数里。 **********************************************************/ #include <iostream> using namespace std; class Temp { public: Temp() { ++m_n; m_sum += m_n; } static void Reset(){m_n = 0; m_sum = 0;} static int getSum(){return m_sum;} private: static int m_n; static int m_sum; }; int Temp::m_n = 0; int Temp::m_sum = 0; int Sum(int n) { Temp::Reset(); Temp *tmp = new Temp ; delete[] tmp; tmp = NULL; return Temp::getSum(); } int main() { cout<<Sum(100)<<endl; return 0; }
9. 输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。
/**************************************************************
题目:输入一个已经按升序排序过的数组和一个数字, 在数组中查找两个数,
使得它们的和正好是输入的那个数字。 要求时间复杂度是O(n)。如果有多对
数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
**************************************************************/
#include <iostream>
using namespace std;
void find(int R[],int n,int sum);
int main()
{
int arr[6] = {1,2,4,7,11,15};
int sum = 15;
find(arr,6,sum);
return 0;
}
void find(int R[],int n,int sum)
{
int i=0;
int j=n-1;
while(i < j)
{
if(R[i]+R[j] == sum)
{
cout<<sum<<" = "<<R[i]<<" + "<<R[j]<<endl;
return;
}
R[i]+R[j]<sum ? ++i : --j;
}
cout<<"Cannot find!"<<endl;
}
10. 约瑟夫环
/****************************************************************************
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,每次从这个圆圈中删除第m个数字
(第一个为当前数字本身,第二个为当前数字的下一个数字)。当一个数字删除后,从被删除
数字的下一个继续删除第m个数字。求出在这个圆圈中剩下的最后一个数字。
分析:既然题目有一个数字圆圈,很自然的想法是我们用一个数据结构来模拟这个圆圈。
在常用的数据结构中,我们很容易想到用环形列表。我们可以创建一个总共有m个数字的环形列表,
然后每次从这个列表中删除第m个元素。 我们用STL中std::list来模拟这个环形列表。
由于list并不是一个环形的结构,因此每次跌代器扫描到列表末尾的时候,
要记得把跌代器移到列表的头部。这样就是按照一个圆圈的顺序来遍历这个列表了。
这种思路需要一个有n个结点的环形列表来模拟这个删除的过程,因此内存开销为O(n)。
而且这种方法每删除一个数字需要m步运算,总共有n个数字,因此总的时间复杂度是O(mn)。
****************************************************************************/
#include <iostream>
using namespace std;
#include <list>
int getLastNumber(list<int> numList,unsigned m);
int main()
{
list<int> numList;
unsigned n;
unsigned m;
cout<<"请输入n:";
cin>>n;
cout<<"请输入m:";
cin>>m;
if(n<1 || m<1)
{
cout<<"\n输入有误!\n"<<endl;
return -1;
}
for(unsigned i=0;i<n;++i)
numList.push_back(i);
cout<<"Last Number: "<<getLastNumber(numList,m)<<endl;
return 0;
}
int getLastNumber(list<int> numList, unsigned m)
{
list<int>::iterator currentIter = numList.begin();
list<int>::iterator nextIter;
while(numList.size() > 1)
{
for(unsigned i=1;i<m;++i)
{
++currentIter;
if(currentIter == numList.end())
currentIter = numList.begin();
}
// 找到第m个数,将其从list中移出
nextIter = ++currentIter;
if(nextIter == numList.end())
nextIter = numList.begin();
--currentIter;
numList.erase(currentIter);
currentIter = nextIter;
}
return *(currentIter);
}
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- 关于指针的一些事情
- c++ primer 第五版 笔记前言
- share_ptr的几个注意点
- Lua中调用C++函数示例
- Lua教程(一):在C++中嵌入Lua脚本
- Lua教程(二):C++和Lua相互传递数据示例
- PHP程序员面试 切忌急功近利(更需要注重以后的发展)
- C++联合体转换成C#结构的实现方法
- C++编写简单的打靶游戏
- C++ 自定义控件的移植问题
- C++变位词问题分析
- C/C++数据对齐详细解析
- C++基于栈实现铁轨问题
- C++中引用的使用总结
- 使用Lua来扩展C++程序的方法
- C++中调用Lua函数实例
- Lua和C++的通信流程代码实例
- C与C++之间相互调用实例方法讲解
- C++ Custom Control控件向父窗体发送对应的消息