滴滴2017秋招编程题

[编程题] 连续最大和

时间限制:1秒
空间限制:32768K
一个数组有 N 个元素,求连续子数组的最大和。 例如:[-1,2,1],和最大的连续子数组为[2,1],其和为 3
输入描述:
输入为两行。
第一行一个整数n(1 <= n <= 100000),表示一共有n个元素
第二行为n个数,即每个元素,每个整数都在32位int范围内。以空格分隔。
输出描述:
所有连续子数组中和最大的值。
输入例子1:
3
-1 2 1
输出例子1:
3

解析:

用f[i]表示以元素i结尾的子数组的最大元素和,则:
f[i] = a[i] , i==0 或者 f[i-1] < 0 (前面的元素和小于0,则可以直接抛弃)
f[i] = f[i-1] + a[i] , f[i-1] > 0
然后求出max(f[i])即可。

c++代码实现:

#include <iostream>

using namespace std;

long long maxSubSum(int *a,int n)
{
    long long sum = 0;
    long long result = -2147483648;
    for(int i=0; i<n; i++){
        if(sum<=0)
            sum = a[i];
        else
            sum += a[i];
        if(sum > result)
            result = sum;
    }
    return result;
}

int main()
{
    int n;
    cin>>n;
    if(n<=0)
        return 0;
    int a[n];
    for(int i=0; i<n; i++){
       cin>>a[i];
    }
    cout<<maxSubSum(a,n);
    return 0;
}

[编程题] 餐馆

时间限制:1秒
空间限制:32768K
某餐馆有n张桌子,每张桌子有一个参数:a 可容纳的最大人数; 有m批客人,每批客人有两个参数:b人数,c预计消费金额。 在不允许拼桌的情况下,请实现一个算法选择其中一部分客人,使得总预计消费金额最大
输入描述:
输入包括m+2行。
第一行两个整数n(1 <= n <= 50000),m(1 <= m <= 50000)
第二行为n个参数a,即每个桌子可容纳的最大人数,以空格分隔,范围均在32位int范围内。
接下来m行,每行两个参数b,c。分别表示第i批客人的人数和预计消费金额,以空格分隔,范围均在32位int范围内。
输出描述:
输出一个整数,表示最大的总预计消费金额
输入例子1:
3 5
2 4 2
1 3
3 5
3 7
5 9
1 10
输出例子1:
20

解析:

贪心算法。将客人信息按照:金额降序,人数升序进行排序。然后将桌子按容量进行升序排序。然后枚举每批客人查找当前最适合的桌子容量,采用二分查找。

C++代码实现:

#include <iostream>
#include <algorithm>
#include <set>
using namespace std;

typedef struct{
    int num;
    int money;
}Customer;

unsigned long long maxIncoming(int n,int m,int *container,Customer* customer)
{
    multiset<int> table(container,container+n);
    sort(customer,customer+m,[](const Customer &c1,const Customer& c2){
        if(c1.money != c2.money)
            return c1.money > c2.money;
        return c1.num < c2.num;
    });
    unsigned long long total = 0;
    for(int i=0; i<m; i++){
        auto it = table.lower_bound(customer[i].num);
        if(it!=table.end()){
            total += customer[i].money;
            table.erase(it);
        }
    }
    return total;
}

int main()
{
    int n,m;
    cin>>n>>m;
    int container[n];
    Customer customer[m];
    for(int i=0; i<n; i++)
        cin>>container[i];
    for(int i=0; i<m; i++)
        cin>>customer[i].num>>customer[i].money;
    cout<<maxIncoming(n,m,container,customer);
    return 0;
}

[编程题] 地下迷宫

时间限制:1秒
空间限制:32768K
小青蛙有一天不小心落入了一个地下迷宫,小青蛙希望用自己仅剩的体力值P跳出这个地下迷宫。为了让问题简单,假设这是一个n*m的格子迷宫,迷宫每个位置为0或者1,0代表这个位置有障碍物,小青蛙达到不了这个位置;1代表小青蛙可以达到的位置。小青蛙初始在(0,0)位置,地下迷宫的出口在(0,m-1)(保证这两个位置都是1,并且保证一定有起点到终点可达的路径),小青蛙在迷宫中水平移动一个单位距离需要消耗1点体力值,向上爬一个单位距离需要消耗3个单位的体力值,向下移动不消耗体力值,当小青蛙的体力值等于0的时候还没有到达出口,小青蛙将无法逃离迷宫。现在需要你帮助小青蛙计算出能否用仅剩的体力值跳出迷宫(即达到(0,m-1)位置)。
输入描述:
输入包括n+1行:
第一行为三个整数n,m(3 <= m,n <= 10),P(1 <= P <= 100)
接下来的n行:
每行m个0或者1,以空格分隔
输出描述:
如果能逃离迷宫,则输出一行体力消耗最小的路径,输出格式见样例所示;如果不能逃离迷宫,则输出”Can not escape!”。
测试数据保证答案唯一
输入例子1:
4 4 10
1 0 0 1
1 1 0 1
0 1 1 1
0 0 1 1
输出例子1:
[0,0],[1,0],[1,1],[2,1],[2,2],[2,3],[1,3],[0,3]

解析:

深度搜索。从起点开始,有四个方向可以走,每走一步,判断其是否到达出口且体力大于0,如果是,则表示找到一条路径,更新路径信息;如果不是出口,则依次探测4个方向。直至所有路径遍历完毕。代码有详细解释。

C++代码实现:

#include <iostream>
#include <vector>
using namespace std;

typedef struct Point{
    int row;
    int col;
    Point(int x,int y):row(x),col(y){}
    Point():row(0),col(0){}
}Point;

int direction[4][2] = {{1,0},{0,1},{-1,0},{0,-1}};
int cost[4] = {0,-1,-3,-1};
int maze[10][10];
int n,m,p;
vector<Point> bestPath;
vector<Point> curPath;
int maxPower = 0x80000000;

void printPath()
{
    int i=0;
    for(; i<bestPath.size()-1; i++)
        cout<<"["<<bestPath[i].row<<","<<bestPath[i].col<<"],";
    cout<<"["<<bestPath[i].row<<","<<bestPath[i].col<<"]";
}

void findPath(int x,int y,int curPower)
{
    //将当前节点加入路径中标记为visited
    curPath.push_back(Point(x,y));
    maze[x][y] = 2;             //visited

    //到达出口,找到一条路径
    if(x==0 && y==m-1 && curPower>=0){  //找到一条路径
        if(curPower > maxPower){
            bestPath = curPath;
            maxPower = curPower;
        }
        curPath.pop_back();     //回退至上一步
        maze[x][y] = 1;         //还原
        return;
    }
    //当前节点并非出口,且体力不为0,则往4个方向上继续探测
    if(curPower>=0){
        for(int i=0; i<4; i++){
            int cx = x+direction[i][0];
            int cy = y+direction[i][1];
            int cp = curPower+cost[i];
            if(cx>=0 && cx<=n && cy>=0 && cy<=m && cp>=0 && maze[cx][cy]==1)
                findPath(cx,cy,cp);
        }
    }
    curPath.pop_back();     //回退至上一步
    maze[x][y] = 1;         //还原
}

int main()
{
    cin>>n>>m>>p;
    for(int i=0; i<n; i++){
        for(int j=0; j<m; j++)
            cin>>maze[i][j];
    }
    findPath(0,0,p);
    if(maxPower>=0)
        printPath();
    else
        cout<<"Can not escape!";
    return 0;
}

[编程题] 末尾0的个数

时间限制:1秒
空间限制:32768K
输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2
输入描述:
输入为一行,n(1 ≤ n ≤ 1000)
输出描述:
输出一个整数,即题目所求
输入例子1:
10
输出例子1:
2

解析

分析一下末尾0会在什么情况下出现?
(1) 5(数字末尾位5)乘于一个偶数,结果肯定有0;
(2)数字末尾就是0的,结果也有0;
第二条可以转变成5*x的形式,比如15=5*3,25=5*5
因此,计算n!结果中末尾0的个数,只需要找到[1-n] n个数中,因子5的个数。
注意:类似于25,可以拆分成5*5,需要注意。

C++代码实现:

#include <iostream>
using namespace std;

int endWithZero(int n)
{
    if(n<5)
        return 0;
    int count = 0, i,j;
    for(i=5; i<=n; i+=5){
        j = i;
        while(j%5==0){
            count++;
            j /= 5;
        }
    }
    return count;
}

int main()
{
    int n;
    cin>>n;
    if(n<1 || n>1000)
        return 0;
    cout<<endWithZero(n);
    return 0;
}

[编程题] 进制转换

时间限制:1秒
空间限制:32768K
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数
输入描述:
输入为一行,M(32位整数)、N(2 ≤ N ≤ 16),以空格隔开。
输出描述:
为每个测试实例输出转换后的数,每个输出占一行。如果N大于9,则对应的数字规则参考16进制(比如,10用A表示,等等)
输入例子1:
7 2
输出例子1:
111

解析:

(1)注意负数,需要转换成正数;
(2)如果是-2147483648,转换位正数是214748648,超出了32位int范围,得用unsigned int或者long 。

c++代码实现:

#include <iostream>

using namespace std;

string factor = "0123456789ABCDEF";

void decToN(int num,int n)
{
    if(num==0){
        cout<<0;
        return;
    }
    bool flag = true;
    unsigned int m = 0;
    if(num<0){
        m = ~num + 1;   //注意-2147483648 ~ 2147483647
        flag = false;
    }
    else
        m = num;
    int index = 31;
    char str[32]={0};
    while(m!=0){
        str[index--] = factor[m%n];
        m /= n;
    }
    if(!flag)
        cout<<'-';
    for(int i=index+1; i<32; i++)
        cout<<str[i];
}

int main()
{
    int m,n;
    cin>>m>>n;
    if(n<2 || n>16)
        return 0;
    decToN(m,n);
    return 0;
}

[编程题] 数字和为sum的方法数

时间限制:1秒
空间限制:32768K
给定一个有n个正整数的数组A和一个整数sum,求选择数组A中部分数字和为sum的方案数。
当两种选取方案有一个数字的下标不一样,我们就认为是不同的组成方案。
输入描述:
输入为两行:
第一行为两个正整数n(1 ≤ n ≤ 1000),sum(1 ≤ sum ≤ 1000)
第二行为n个正整数Ai,以空格隔开。
输出描述:
输出所求的方案数
输入例子1:
5 15
5 5 10 2 3
输出例子1:
4

解析:

(1)深度搜索。先对数组降序排序。然后用深度搜索。注意递归容易超时,需要用一个额外的数组来保存中间结果。
(2)动态规划。dp[i][j]代表前i个元素和为j的方案数量。
初始:dp[i][0] = 1(全部元素都不取,则和为0), dp[0][j] = 0;
推导方程:
dp[i][j] = dp[i-1]j + dp[i-1][j-num[i]] (取第i个元素),if(j>=num[i])
dp[i][j] = dp[i-1][j], if (j < num[i])。

C++代码实现:
深度搜索

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

int num[1000] = {0};
int sum = 0;
int n = 0;
vector<vector<long long>> dp;

long long dfs(int last,int restSum)
{
    if(restSum==0)
        return 1;
    if(dp[last][restSum]!=-1)
        return dp[last][restSum];
    long long count = 0;
    for(int i=last; i<n; i++){
        if(restSum >= num[i])
            count += dfs(i+1,restSum-num[i]);
    }
    dp[last][restSum] = count;
    return count;
}

long long numberOfSum()
{
    sort(num,num+n,greater<int>());
    return dfs(0,sum);
}

int main()
{
    cin>>n>>sum;
    dp.resize(n+1,vector<long long>(sum+1,-1));
    for(int i=0; i<n; i++)
        cin>>num[i];
    cout<<numberOfSum();
    return 0;
}

动态规划

#include <iostream>
using namespace std;

int num[1000] = {0};
int sum = 0;
int n = 0;
long long dp[1001][1001]={0};


long long numberOfSum()
{
    for(int j=0; j<1001; j++)
        dp[0][j] = 0;
    for(int i=0; i<1001; i++)
        dp[i][0] = 1;         //前i个元素和为0只有一种方案,就是全都不取

    for(int i=1; i<=n; i++){
        for(int j=0; j<=sum; j++){
            if(j>=num[i-1])
                dp[i][j] = dp[i-1][j] + dp[i-1][j-num[i-1]];
            else
                dp[i][j] = dp[i-1][j];
        }
    }
    return dp[n][sum];
}

int main()
{
    cin>>n>>sum;
    for(int i=0; i<n; i++)
        cin>>num[i];
    cout<<numberOfSum();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/peaktravel/article/details/77743295
今日推荐