滴滴2017秋招笔试刷题

不会做的题参考牛客网上其他人的代码,加上自己的理解


Q1.连续最大和
一个数组有N个元素有正有负,找出连续的子数组使得和最大。
说明:以第i个元素结尾,与以第i-1个元素结尾比较连续子数组最大和,
如果用一维数组dp保存以第i个元素结尾时的最大连续子数组和。
dp[i]=max(a[i],dp[i-1]+a[i]);
dp[0]=a[0];
找到dp[i]中最大的即可。

#include<iostream>
#include<algorithm>
#include<limits.h>
using namespace std;
int findmax(int a[], int n)//同样的思想可以写的更简洁,暂时不想写了
{
    int dp[n],maxsum=INT_MIN;
    for(int i=0;i<n;i++)
        {
        if(i==0)
            dp[0]=a[0];
        else
            dp[i]=max(a[i],a[i]+dp[i-1]);
    }
    for(int i=0;i<n;i++)
     {
        if(dp[i]>maxsum)
            maxsum=dp[i];
    }  
    return maxsum;
}
int main()
{
    int n, a[100000];
    cin >> n;
    for (int i = 0; i < n; ++i)
        cin >> a[i];
    int result=findmax(a,n);
    cout << result << endl;
    return 0;
}

Q2.餐馆问题
参观有n张桌子,分别能容纳一定人数,有m行人,分别有一定人数,消费一定金额,不允许拼桌,找出最大的收入金额。
下面的代码AC没通过,测试用例通过率90%,问题出在超时了!!!

#include<iostream>
#include<vector>
#include<math.h>
#include<algorithm>
using namespace std;

struct P{
    int num;
    int val;
    P(int x, int y) :num(x), val(y){}
};
bool compare(P p1, P p2)
{
return p1.num<p2.num||p1.num==p2.num&&p1.val<p2.val;
}

vector<int> a;
vector<P> v;
long long result=0;
int main()
{
    int n, m,x,y;
    cin >> n >> m;
    a.resize(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    sort(a.begin(),a.end());
    for (int i = 0; i < m; i++)
    {
        cin >> x >> y;
        v.push_back(P(x,y));
    }
    sort(v.begin(), v.end(), compare);
    //桌号从小到大,分别找到能赚的最多的钱
    for (int i = 0; i < n; i++)
    {
        int pos = -1,money=0,j=0;
            while(a[i] >= v[j].num&&j<m)
            {
                if (v[j].val>money)
                {
                    money = v[j].val;
                    pos = j;
                }
                j++;
            }
        if (pos != -1)
        {
            v[pos].val = 0;
        }
        result += money;
    }
    cout << result << endl;
    return 0;
}
//参考他人代码,用STL中的multiset存储桌子大小信息,并用set带有的函数处理,不超时。。之前没用过set,补了很多相关知识只是看懂了,还需要再练习。。。
#include<iostream>
#include<vector>
#include<math.h>
#include<set>
#include<algorithm>
using namespace std;
struct P{
    int num;
    int val;
    P(int x, int y) :num(x), val(y){}
};
bool compare(P p1, P p2)
{
    return p1.val > p2.val || p1.val == p2.val&&p1.num > p2.num;
}
multiset<int> a;
long long result = 0;
int main()
{
    vector<P> v;
    int n, m,x,y;
    cin >> n >> m;
    for (int i = 0; i < n; i++)
    {
        int t;
        cin >> t;
        a.insert(t);
    }
    for (int i = 0; i < m; i++)
    {
        cin >> x >> y;
        v.push_back(P(x,y));
    }
    sort(v.begin(), v.end(), compare);
    for (auto i : v)
    {
        auto table = a.lower_bound(i.num);
        if (table != a.cend())
        {
            result += i.val;
            a.erase(table);
        }
        if (a.empty()) break;
    }
    cout << result << endl;
    return 0;
}

Q3.地下迷宫
n*m的迷宫,入口在(0,0),出口在(0,m-1),上下左右移动,左右移动消耗1点体力值,上移3点,下移0点,初始有一个体力值k。输入n,m,k,然后输入迷宫,找到消耗体力最小的路径并输出。
代码非原创,只是加上注释,方便理解

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int const maxn = 15;
int ans = -1;
int r,c;
int data[maxn][maxn];//保存迷宫图
int vis[maxn][maxn];//与迷宫图同样大小的矩阵,用于辅助记录已走过的点,不走回头路
int dr[]={0,0,-1,1};//四个移动方向
int dc[]={-1,1,0,0};
int dv[]={1,1,3,0};//分别消耗的体力

struct P{//保存坐标
    int r;
    int c;
    P(int a1=0,int a2=0):r(a1),c(a2){}
    friend ostream& operator<<(ostream& os,P p1);
};
ostream& operator<<(ostream& os,P p1) {//便于输出
    os<<"["<<p1.r<<","<<p1.c<<"]";
    return os;
}
vector<P> V,vp;//V保存能到达出口的路径结果,并且会更新保存体力值消耗最小的结果,v则保存递归时的临时结果
int live = -1, init;//live为-1表示没有找到路径,找到时保存剩余体力最大的值
void dfs(int rr,int cc) {
    if(rr==0&&cc==c-1&&init>=0) {//达到出口时判断是否是体力消耗值当前最小,是则保存路径和剩余体力值
        if(init>=live) {
            live = init;
            V = vp;
        }
    } else {
         for (int i=0;i<4;i++) {//4个方向都尝试走一步
             int nr = rr+dr[i];
             int nc = cc+dc[i];
             if(nr>=0&&nr<r&&nc>=0&&nc<c&&data[nr][nc]&&!vis[nr][nc]) {//如果没有走出边界而且是之前没有走过的点而且是可走的点
                    init-=dv[i];//减掉这一步需要消耗的体力
                    vis[nr][nc]=1;//另一个二维数组只是为了保存已走过的点,在下一次迭代时不会再往回走
                    vp.push_back(P(nr,nc));//把这个点放到临时的vp中
                    dfs(nr,nc);//在当前节点上再次dfs,注意如果未走到出口会一直dfs直到无路可走
                    init+=dv[i];//以下三步表示找到结果或者无路可走了都要退回到起点。
                    vis[nr][nc]=0;
                    vp.pop_back();
             }
         }
    }
}


int main() {
    cin>>r>>c>>init;
    for (int i=0;i<r;i++) {
        for(int j=0;j<c;j++) {
            cin>>data[i][j];
        }
    }
    vis[0][0]=1;//先把起点放进vp并标志已走过
    vp.push_back(P(0,0));
    dfs(0,0);
    if(live!=-1) {
        cout<<V[0];
        for (int i=1;i<V.size();i++)
        cout<<","<<V[i];
        cout<<endl;
    } else {
        cout<<"Can not escape!"<<endl;
    }
}

笔试题里很多dfs之类的题,需要专项练习。。。


Q4.末尾0的个数
输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2
之前遇到过的题,简单说n!=2^n+3^m+5^k+…,理解一下就是由2和5的个数决定,显然2的个数n>k,所以最后0的个数等于k。
遇到5^2就要加2此,5^3就要加3次…

#include<iostream>
using namespace std;
    int count=0;
int main()
    {
    int n;
    cin>>n;

    n=n-n%5;
    while(n)
        {
        int x=n;
        while(n%5==0)
            {
            count++;
            n=n/5;
        }
        n=x;
        n-=5;
    }
    cout<<count<<endl;
    return 0;
}

Q5.进制转换
给定一个十进制数M,以及需要转换的进制数N。将十进制数M转化为N进制数

#include<iostream>//写的比较繁琐,懒得改了。。。题目比较简单
using namespace std;

int main()
{
    int M,N;
    string s = "ABCDEF";
    cin >> M>>N;
    if(M<0)
        {
        cout<<'-';
        M/=-1;
    }

    int a[35], b[35];
    int i = 0;
    while (M)
    {
        a[i++] = M%N;
        M /= N;
    }
    for (int j = i - 1; j >= 0; j--)
    {
        b[i - 1 - j] = a[j];
        {
            if (b[i - 1 - j] < 10)
                cout << b[i - 1 - j];
            else
                cout << s[b[i - 1 - j] - 10];
        }
    }
    return 0;
}

Q6数字和为sum的方法数
输入n个数,给定一个和m,从这n个数中选出部分数使和为m。(题目表述不清楚,但是如果n个数的和刚好为m也是可以的)

说明:这一题优点类似背包问题,而且在leetcode上刷到过类似的题。
需要用到动态规划的思想。
一个二维dp数组。
dp[i][j]表示以第i个数为结尾,满足和为j的方法数。
转移方程为:
dp[i][j]=dp[i-1][j-a[i]]+dp[i-1][j];(如果a[i]<=j)
这说明结果应该等于以第i-1个数结尾找结果为j-a[i]的方法数+去掉a[i],以第i-1个数为结尾找结果为j的方法数
dp[i][j]=dp[i-1][j];(如果a[i]>j)
这说明a[i]不可用,直接往前推一步即可
dp[0][0]=1;0个数找和为0,显然方法数为1。(dp[0]0”>x=0,显然)

const int MaxN = 1005;
long long int dp[MaxN][MaxN];//注意:第一方法数可能超过Int的范围,第二需要声明全局,不然会stack overflow

int main()
{
    int N, M;
    cin >> N >> M;
    dp[0][0] = 1;
    vector<int> vec(N+1);
    //vec.resize(N + 1);(如果vec定义为全局就在这里resize限定大小)
    for (int i = 1; i <= N; i++)
        cin >> vec[i];
    for (int i = 1; i <= N; i++)
    {
        for (int j = M; j >= 0; j--)
        {
            if (j >= vec[i])
                dp[i][j] = dp[i - 1][j - vec[i]] + dp[i - 1][j];
            else
                dp[i][j] = dp[i - 1][j];
        }
    }
    cout << dp[N][M] << endl;
    system("pause");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值