c++数据结构例题

来源:互联网 发布:监控数据恢复 编辑:程序博客网 时间:2024/06/01 11:53

由于二面boss时被boss的两道算法题难住了(ps:本人应聘的是ios开发岗位,oc语言),没什么好说的了,只能怪自己太年轻了。回来后开始脑补各公司的数据结构与算法面试题。

先从已有答案的面试题开始模仿及学习c++语言。点击打开链接 点击打开链接

再从没有答案的面试题开始自己写(遇事不懂问度娘~)。点击打开链接

环境:mac,xcode或者终端;

语言:c++;

潇洒的分割线~哗——————————————————————————————————————————————————


例1:求一个数组的最长递减子序列比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}

算法描述:

1.      对原序列进行递减排序(选择快速排序法);

2.      删掉重复数字;

3.      得到子序列。


c++代码:

#include <iostream>using namespace std;#define MAX_SIZE 9void FastSort(int a[],int left,int right){    if (left < right) {    int i = left,j = right;    int temp = a[left];    while (i<j) {        while (j>i&&a[j]>temp) {            j--;        }        a[i]=a[j];        while (i<j&&a[i]<=temp) {            i++;        }        a[j]=a[i];    }    a[i]=temp;    FastSort(a, i+1, right);    FastSort(a, left, i-1);    }}void getChildSet(int a[],int p[],int n,int& length){    for (int i=0; i<n; i++) {        if (a[i]!=a[i+1]) {            p[length]=a[i];            length++;        }    }}int main(int argc, const char * argv[]) {    int a[MAX_SIZE] = {2,3,4,1,5,6,9,7,6};    for (int i= 0; i<MAX_SIZE; i++) {        cout<<a[i];    }    cout<<":";    FastSort(a, 0, MAX_SIZE-1);    int p[MAX_SIZE];    int length = 0;    getChildSet(a,p,MAX_SIZE,length);    for (int i=0; i<length; i++) {        cout<<p[i];    }    cout<<"\n";    return 0;}
运行结果:234156976:12345679

收获:序列的快速排序,题目的改动,正序排列,删除重复项。

例2:将一整数序列逆序(要求递归实现)

算法描述:
1当满足first<last时直接交换序列首位和末尾位元素;
2.递归调用(注意递归退出条件:必须是变量first大于或等于last)

c++代码:

#include <iostream>using namespace std;#define MAX_SIZE 9void FastSort(int a[],int left,int right){    if (left >= right) return;    int temp = a[left];    a[left] = a[right];    a[right] = temp;            FastSort(a, left+1, right-1);}int main(int argc, const char * argv[]) {    int a[MAX_SIZE] = {1,2,3,4,5,6,7,8,9};    for (int i=0; i<MAX_SIZE; i++) {        cout << a[i];    }    cout << ":";    FastSort(a, 0, MAX_SIZE-1);    for (int i=0; i<MAX_SIZE; i++) {        cout << a[i];    }    cout << "\n";    return 0;}


运行结果:1234567892:2987654321
收获:关键在于数组的长度奇偶性。递归思想


例3:将一整数逆序后放入一数组中(要求递归实现)如:12345逆置后为54321
算法描述:
1分割出整数的每一个位,方法n%10;
2.每一次分割都是得到整数最后一个位,数组索引值要从第0开始


c++代码:

#include <iostream>using namespace std;void FastSort(int a[],int n,int& length){    if (n == 0) return;    a[length] = n%10;    length++;    FastSort(a, n/10,length);}int main(int argc, const char * argv[]) {    int n = 1234567890;    int length = 0;    cout << n <<":";    int a[100];    FastSort(a, n, length);    for (int i=0; i<length; i++) {        cout << a[i];    }    cout << "\n";    return 0;}

运行结果:1234567890:0987654321

收获:/10与%10的灵活运用。


例4:递归实现回文判断(如:abcdedbca就是回文,判断一个面试者对递归理解的简单程序)
算法描述:
与求一个序列的转置类似。


c++代码:

#include <iostream>using namespace std;bool FastSort(char* str,int left,int right){    if (left > right) {        return false;    }    if (left == right) {        return true;    }    if (str[left] != str[right]) {        return false;    }else return(FastSort(str,left+1,right-1));    }int main(int argc, const char * argv[]) {    char* str = "abcdedcba";    cout<<str<<":";    int count = strlen(str);    if(FastSort(str, 0, count-1))        cout<<"yes"<<endl;    else cout<<"no"<<endl;    return 0;}

运行结果:abcdedcba:yes      ;    abcddcba:no     ;

收获:字符串也可像数组那样直接str[index]取。注意字符串最后一个是“\0”!自定义函数从void扩展到bool,注意return。


例5:分解成质因数(如435234=251*17*17*3*2)
算法描述:
1 寻找一个整数的质因数方法从2开始遍历,依次查找

c++代码:

#include <iostream>using namespace std;void func(int n,int i){    while (n%i !=0) {        i++;        if (i*i > n) {            i = n;            break;        }    }    if (i != n) {        func(n/i, i);        cout<<"*"<<i;    }else cout<<n;}int main(int argc, const char * argv[]) {    int n = 435234;    cout<<n<<"=";    func(n, 2);    cout<<"\n";    return 0;}

运行结果:435234=251*17*17*3*2

收获:分解质因数,简单而有深度的题!改动的地方在于i*i>n,判断一个数是不是质数,不需要从2到n,只需从2到根号n!


例6:寻找迷宫的一条出路,1代表障碍,0代表通。
算法描述:
这里可以使用几种方法,我知道的有使用《数据结构》上“穷举求解”的方法,还有就是使用遗传算法寻找最优路径。这里我先简单描述下“穷举求解”,然后再做遗传算法的方式。
1 问题中要涉及走过路径的回溯,因为栈是先进后出,所以利于回溯,选择栈来存储走过路径
2 每一步有四个方向可以走,每到一步依次判断每一个方向,只要判断到某个方向可走就选择这个方向前进。
3 当所有方向都不能行进时,回溯到上一步,此时判断栈顶指针是否为-1,如果是,返回false失败,否则递归调用继续寻找。

c++代码:

#include <iostream>using namespace std;#define MAX_SIZE 10int maze[MAX_SIZE][MAX_SIZE]={    {1,1,1,1,1,1,1,1,1,1},    {1,0,0,1,0,1,0,1,0,1},    {1,0,0,1,0,0,0,1,0,1},    {1,0,0,0,0,1,1,0,0,1},    {1,0,1,1,1,0,0,0,0,1},    {1,0,0,0,1,0,0,0,0,1},    {1,0,1,0,0,0,1,0,0,1},    {1,0,1,1,1,0,1,1,0,1},    {1,1,0,0,0,0,0,0,0,1},    {1,1,1,1,1,1,1,1,1,1}};typedef struct{    int x;    int y;}POINT;typedef struct{    POINT data[MAX_SIZE * MAX_SIZE];    int top;}STACK;void findWay(int maze[][MAX_SIZE],POINT start,POINT end,STACK& way){    POINT step;    step.x = start.x;    step.y = start.y;    if (way.data[way.top].x != end.x || way.data[way.top].y != end.y)    {        //left        if (!maze[step.y][step.x+1]) {            maze[step.y][step.x] = 1;            way.top++;            way.data[way.top] = step;            step.x++;            findWay(maze, step, end, way);        }        //down        else if (!maze[step.y+1][step.x]) {            maze[step.y][step.x] = 1;            way.top++;            way.data[way.top] = step;            step.y++;            findWay(maze, step, end, way);        }        //right        else if (!maze[step.y][step.x-1]) {            maze[step.y][step.x] = 1;            way.top++;            way.data[way.top] = step;            step.x--;            findWay(maze, step, end, way);        }        //up        else if (!maze[step.y-1][step.x]) {            maze[step.y][step.x] = 1;            way.top++;            way.data[way.top] = step;            step.y--;            findWay(maze, step, end, way);        }        else{            if (way.top == -1)                return;            maze[step.y][step.x] = 1;            way.top--;            step = way.data[way.top];            findWay(maze, step, end, way);        }    }}int main(int argc, const char * argv[]) {    POINT start,end;    start.x = 1;    start.y = 1;    end.x = 8;    end.y = 8;    STACK way;    way.top = -1;    findWay(maze, start, end, way);    if (way.top != -1) {        cout<<"Have fount the way!"<<endl;        for (int i = 0; i < way.top; i++) {            cout<<"("<<way.data[i].x<<" , "<<way.data[i].y<<"),";        }    }    else cout<<"Don't find the way"<<endl;    return 0;}

运行结果:Have fount the way!(1 , 1),(2 , 1),(2 , 2),(2 , 3),(2 , 3),(1 , 3),(1 , 4),(1 , 5),(2 , 5),(3 , 5),(3 , 6),(4 , 6),(5 , 6),(5 , 7),(5 , 8),(6 , 8),(7 , 8)

收获:矩阵里的坐标跟眼睛看到的坐标反一下就好。穷举法。一个点有路就走,前脚走后脚封路,没路可走退回一步封路。用遗传算法求最优路径,待定!学过oc,对于.的用法、对象、属性还是理得清的,比较好理解。


80题-例3:求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。

c++代码:

#include <iostream>using namespace std;int func(int a[],int length){    int smin = 0;    int smax = 0;    int sminInmax = 0;    int sum = 0;    for (int i=0; i < length; i++) {        sum += a[i];        if (sum > smax) {            smax = sum;            smin = sminInmax;        }        if (sum < smin) {            sminInmax = sum;        }    }    return smax-smin;}int main(int argc, const char * argv[]) {    //int a[8] = {1,-2,3,10,-4,7,2,-5};    int a[8] = {-1,2,3,4,5,6,-10,11};    int result = func(a, 8);    cout<<result;    return 0;}

运行结果:21

收获:这题关键在于时间复杂度要求,所以就遍历一次。思路,连续n-m个数求和=1到n个求和-1到m个求和,求最大值=1到n求和的最大值-最小值。由于可能最小值的数组长度大于最大值的数组长度,这样相减结果不是我们要的,于是引入延迟最小值!当最大值更新了,再去刷新最小值。遗憾的是主要还是用到数学思想,没用到计算机思想(毕竟本人曾是数学竞赛的0.0)

补充:计算机思想。f(n-1)表示前面已找到的最大值,若f(n-1)<0,则f(n)=a[n];否则f(n)=f(n-1)+a[n];

c++代码(终端):

#include <iostream>#include <vector>using namespace std;int main(){vector<int> a;int temp;while(cin >> temp){a.push_back(temp);} if(a.size() == 0){return -1;}int last = a[0];int max = a[0];for(int i = 1; i < a.size(); i++){if(last > 0){last += a[i];}else {last = a[i];}if(max < last){max = last;}}cout << max << endl;return 0;}

题80-例5:查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

c++代码:

#include <iostream>using namespace std;#define n 8#define k 4void func(int a[],int left,int right){    int i = left, j = right;    int temp = a[left];        if (left<right) {        while (i<j) {            while (i<j&&a[j]>temp) {                j--;            }            a[i] = a[j];            while (i<j&&a[i]<=temp) {                i++;            }            a[j]=a[i];        }        a[i]=temp;        func(a, left, i-1);        func(a, i+1, right);    }}int main(int argc, const char * argv[]) {    //int a[n] = {1,2,3,4,5,6,7,8};    int a[n];    for (int i=0; i<n; i++) {        cout<<"a["<<i<<"]=";        cin>>a[i];    }        func(a, 0, n-1);    for (int i = 0; i<k; i++) {        cout<<a[i]<<" ";    }    cout<<endl;    return 0;}

运行结果:1,2,3,4

收获:数组的快速排列又巩固一次。


题80-例10:翻转句子中单词的顺序。
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。

句子中单词以空格符隔开。为简单起见,标点符号和普通字母一样处理。
例如输入“I am a student.”,则输出“student. a am I”。

c++代码:

#include <iostream>using namespace std;void func(string str,string comparestr,int right){    int i = right-1;    while (i)    {        if (str.compare(i, 1, comparestr) == 0)        {            for (int j = i+1; j < right ; j++)            {                cout<<str[j];            }            cout<<comparestr;            func(str,comparestr,i);            break;        }        i--;    }    if (i == 0)    {        for (int j = i; j < right ; j++)        {            cout<<str[j];        }    }}int main(int argc, const char * argv[]) {    string str = "I am a student.";    string str1 = " ";    cout<<str<<":";    func(str,str1,str.length());    cout<<endl;        return 0;}

运行结果:I am a student.:student. a am I

收获:string字符串比较。


题80-例12:题目:求1+2+…+n,
要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。

c++代码:

#include <iostream>using namespace std;#define N 10int func(int n,int &sum){    n && func(n-1, sum);    return sum+=n;}int main(int argc, const char * argv[]) {    int sum = 0;    cout<<func(N, sum);        return 0;}

运行结果:55;

收获:这题抄袭网上大牛的,用&&特性跳出循环,膜拜orz!get☑️。


题80-例14:题目:输入一个已经按升序排序过的数组和一个数字,

在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组1、2、4、7、11、15和数字15。由于4+11=15,因此输出4和11。
c++代码:

#include <iostream>using namespace std;#define n 6#define SUM 15void func(int a[],int length,int right){    while (length!=right) {        if ((a[length]+a[right])>SUM) {            right--;        }        else if ((a[length]+a[right])<SUM) {            length++;        }        else {            cout<<a[length]<<"+"<<a[right]<<"="<<SUM<<endl;            break;        }    }    if (length == right) {        cout<<"no result"<<endl;    }}int main(int argc, const char * argv[]) {    int a[n] = {1,2,3,4,11,15};    func(a, 0, n-1);    return 0;}
运行结果:4+11=15

收获:重要题干“已经正序排列”“两个数”。省了很多事了。头尾两指针,sum大了尾针移,小了头针移。


题80-例18:题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。

c++代码:

#include <iostream>using namespace std;#define N 17#define M 5int LastRemaining_Solution2(int n, unsigned int m){    if(n <= 0 || m < 0)        return -1;    int lastinteger = 0;    for (int i = 2; i <= n; i ++)        lastinteger = (lastinteger + m) % i;        return lastinteger;}int main(int argc, const char * argv[]) {        cout<<LastRemaining_Solution2(N, M);    return 0;}

运行结果:10.

收获:约瑟夫环,数学分析一番,递推一番,得出公式:f(n,m)=[f(n-1,m)+m]%n n>1。第一个删除的是M-1.


题80-例19:题目:定义Fibonacci数列如下:
/ 0 n=0
f(n)= 1 n=1
\ f(n-1)+f(n-2) n=2
输入n,用最快的方法求该数列的第n项。

c++代码:

#include <iostream>using namespace std;#define N 6int func(int n){    if (n <= 0) {        return 0;    }    if (n == 1 || n == 2) {        return n;    }    return func(n-1)+func(n-2);}int main(){    cout<<func(N)<<endl;    return 0;    }

运行结果:13

收获:斐波那契数列。


题80-例20:题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。
例如输入字符串"345",则输出整数345。

c++代码:

#include <iostream>using namespace std;int main(int argc, const char * argv[]) {    char* str = "0345";    int length = strlen(str);    int sum = 0;    for (int i = 0 ; i < length; i++) {        sum = sum*10 + str[i]-48;    }    cout<<sum;    return 0;}

运行结果:345

收获:直接通过字符的ASCII码计算。“0”对应48。

题80-例21:2010年中兴面试题
编程求解:
输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,
使其和等于 m ,要求将其中所有的可能组合列出来.

c++代码:

#include <iostream>using namespace std;#define M 8#define N 20void func(int n, int m,int a[]){    if (m == 0) {        for (int i = 1; i < M+1; i++) {            if (a[i] == 1) {                cout<<i<<" ";            }        }        cout<<endl;    }    if (n <= 0 || m <= 0) {        return;    }    a[n] = 0;    func(n-1, m,a);    a[n] = 1;    func(n-1, m-n,a);    a[n] = 0;}int main(){    int a[M+1];    int m = M;    int n = N;    if (n > m) {        n = m;    }    if (m > n*n-n+1) {        cout<<"Don't find!"<<endl;        return 0;    }    func(n, m,a);    return 0;    }

运行结果:1 3 4 ,1 2 5 ,3 5 ,2 6 ,1 7 ,8

收获:0/1背包问题。从右往左,没拿标0,f(n-1,m,a[]);拿了标1,f(n-1,m-n,a[])。看m是否为零。


题80-例27:跳台阶问题
题目:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。
求总共有多少总跳法,并分析算法的时间复杂度。

这道题最近经常出现,包括MicroStrategy等比较重视算法的公司
都曾先后选用过个这道题作为面试题或者笔试题。

c++代码:

#include <iostream>using namespace std;#define N 6int func(int n){    if (n <= 0) {        return 0;    }    if (n == 1 || n == 2) {        return n;    }    return func(n-1)+func(n-2);}int main(){    cout<<func(N)<<endl;    return 0;    }

运行结果:6

收获:Fibonacci数列。


题80-例28:整数的二进制表示中1的个数
题目:输入一个整数,求该整数的二进制表达中有多少个1。
例如输入10,由于其二进制表示为1010,有两个1,因此输出2。

分析:
这是一道很基本的考查位运算的面试题。
包括微软在内的很多公司都曾采用过这道题。

c++代码:

#include <iostream>using namespace std;#define N 10int func(int n){    if (n == 1) {        return 1;    }    if (n%2) {        return func(n/2)+1;    }    return func(n/2);}int main(){    cout<<func(N)<<endl;    return 0;    }

运行结果:2

收获:递归,/2%2.

0 0
原创粉丝点击