c++数据结构例题

由于二面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 9
void 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 9
void 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 10

int 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 4

void 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 10

int 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 15
void 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 5

int 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 6

int 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 20

void 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 6

int 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 10

int 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
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值