1. 程式人生 > >滴滴出行2017秋招筆試真題-程式設計題彙總

滴滴出行2017秋招筆試真題-程式設計題彙總

滴滴的題考經典演算法比較多啊,兩道經典動態規劃,一道經典搜尋題,一道程式設計之美原題(聽別人說是程式設計之美上的,自己並不清楚),兩道水題.

題目連結:[點這兒].

第一題:

題目:連續最大和

求陣列的連續最大和,太經典了,有dp的做法,也有非dp的線性做法,我用的dp.

程式碼:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int main()
{
    int n;
    while (cin >> n) {
        vector
<int>
arr; for (int i = 0; i < n; i++) { int x; cin >> x; arr.push_back(x); } vector<LL> dp(n, 0); LL ans = arr[0]; dp[0] = arr[0]; for (int i = 1; i < n; i++) { dp[i] = dp[i - 1] < 0
? arr[i] : dp[i - 1] + arr[i]; ans = max(dp[i], ans); } cout << ans << endl; } return 0; }

第二題:餐館

題目:

某餐館有n張桌子,每張桌子有一個引數:a 可容納的最大人數; 有m批客人,每批客人有兩個引數:b人數,c預計消費金額。 在不允許拼桌的情況下,請實現一個演算法選擇其中一部分客人,使得總預計消費金額最大

解析:

貪心,很容易想到,消費高並且人數少的客人們是要優先考慮的(店家都喜歡做土豪的生意嘛).其次要把這些客人安排到大小恰到合適的桌子,這樣可以接納更多的客人(避免浪費,店家也最喜歡做這種事).

這樣就可以直接寫出一個複雜度為O(n2)的演算法,但是這個題的資料用這樣的演算法是過不了的,必須優化到O(nlogn)

我們可以想到在O(n2)做法中有個迴圈是找桌子,順序查詢的,這個時候桌子的容量已經排好序了,那麼很容易就可以從這兩個條件看出來可以二分查詢來優化,於是我用了stl中的multiset.lower_bound來實現這個二分.

後來在評論區看到有人用優先佇列做的,其實是一樣的,優先佇列的查詢最大值也是O(logn)的,這種做法只不過是O(lognn)也就是說和我的做法只是迴圈內外層調換了下,有興趣的可以試試.

程式碼:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

bool cmp(const pair<int, int> &A, const pair<int, int> &B)
{
    if (A.second != B.second)
        return A.second > B.second;
    return A.first < B.first;
}

int main()
{
    int n, m;
    while (cin >> n >> m) {
        multiset<int> a;
        vector<pair<int, int> > arr;
        for (int i = 0; i < n; i++) {
            int x;
            cin >> x;
            a.insert(x);
        }
        for (int i = 0; i < m; i++) {
            int x, y;
            cin >> x >> y;
            arr.emplace_back(x, y);
        }
        sort(arr.begin(), arr.end(), cmp);

        LL ans = 0;
        for (int i = 0; i < m && a.size() > 0; i++) {
            auto it = a.lower_bound(arr[i].first);
            if (it != a.end()) {
                ans += arr[i].second;
                a.erase(it);
            }
        }
        cout << ans << endl;
    }
    return 0;
}

第三題:

題目:地下迷宮

小青蛙有一天不小心落入了一個地下迷宮,小青蛙希望用自己僅剩的體力值P跳出這個地下迷宮。為了讓問題簡單,假設這是一個n*m的格子迷宮,迷宮每個位置為0或者1,0代表這個位置有障礙物,小青蛙達到不了這個位置;1代表小青蛙可以達到的位置。小青蛙初始在(0,0)位置,地下迷宮的出口在(0,m-1)(保證這兩個位置都是1,並且保證一定有起點到終點可達的路徑),小青蛙在迷宮中水平移動一個單位距離需要消耗1點體力值,向上爬一個單位距離需要消耗3個單位的體力值,向下移動不消耗體力值,當小青蛙的體力值等於0的時候還沒有到達出口,小青蛙將無法逃離迷宮。現在需要你幫助小青蛙計算出能否用僅剩的體力值跳出迷宮(即達到(0,m-1)位置)。

解析:

bfs,已經寫過太多這種題了,不想寫這個題解析了,可以看看我部落格的其他文章,裡面有這類題的解析.

程式碼:

#include <bits/stdc++.h>

using namespace std;

int dirx[] = {-1, 0, 1, 0};
int diry[] = {0, 1, 0, -1};
int value[] = {3, 1, 0, 1};

struct Node {
    int x, y;
    int p, pre;
    Node(int x, int y, int p, int pre = -1) : x(x), y(y), p(p), pre(pre) {}
    bool operator < (const Node &other) const {
        return p > other.p;
    }
};

int main()
{
    int n, m, p;
    while (cin >> n >> m >> p) {
        vector<vector<int> > mp(n, vector<int>(m));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                int x;
                cin >> x;
                mp[i][j] = x;
            }
        }

        deque<Node> que;
        vector<vector<bool> > used(n, vector<bool>(m, false));
        que.push_back(Node(0, 0, p));

        int head = 0;

        used[0][0] = true;
        bool f = false;
        int ans = 0;
        while (!que.empty()) {
            if (que.begin() + head == que.end())
                break;
            auto now = que[head++];
            if (now.x == 0 && now.y == m - 1) {
                f = true;
                ans = head - 1;
                break;
            }
            for (int i = 0; i < 4; i++) {
                int tx = now.x + dirx[i], ty = now.y + diry[i];
                int tp = now.p - value[i];
                if (tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty] == 1 && !used[tx][ty] && tp >= 0)
                    que.push_back(Node(tx, ty, tp, head - 1)), used[tx][ty] = true;
            }
        }
        if (!f) {
            cout << "Can not escape!" << endl;
        } else {
            stack<int> st;
            while (que[ans].pre != -1)
                st.push(que[ans].pre), ans = que[ans].pre;
            while (!st.empty())
                cout << "[" << que[st.top()].x << "," << que[st.top()].y << "],", st.pop();
            cout << "[" << 0 << "," << m - 1 << "]" << endl;
        }
    }
    return 0;
}

第四題:末尾0的個數

題目:

輸入一個正整數n,求n!(即階乘)末尾有多少個0? 比如: n = 10; n! = 3628800,所以答案為2.

解析:

n!=1×2××k××n。首先分析下什麼時候末尾才會出現0,當k中有5這個因子的時候與偶數相乘就會出現0,因此,這個題轉化為n!中有多少個5因子;

n!=1×2××(51)××9×(52)×24×(551)×(555)×
可以發現有一個5的因子的數是每隔5個就有,有兩個5的因子的數是每隔25個就有,……,那麼很直接的做法就是下面程式碼的做法了(每隔5個數有1個5,然後再是每隔25個數再有1個5,累加起來就好了).

程式碼:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int n;
    while (cin >> n) {
        int ans = 0;
        for (; n; ans += n /= 5);
        cout << ans << endl;
    }
    return 0;
}

第五題:進位制轉換

題目:

給定一個十進位制數M,以及需要轉換的進位制數N。將十進位制數M轉化為N進位制數,M(32位整數)、N(2 ≤ N ≤ 16).

解析:

水題,直接模擬,我的程式碼應該是最簡潔的吧.

#include <bits/stdc++.h>

using namespace std;

const char MP[] = "0123456789ABCDEF";

int main()
{
    int M, N;
    while (cin >> M >> N) {
        stack<int> st;
        bool f = false;
        for (M = M < 0 ? f = true, -M : M; M; st.push(M % N), M /= N);
        for (f ? cout << "-", 0 : 0; !st.empty(); cout << MP[st.top()], st.pop());
        cout << endl;
    }
    return 0;
}

第六題:數字和為sum的方法數

題目:

給定一個有n個正整數的陣列A和一個整數sum,求選擇陣列A中部分數字和為sum的方案數。
當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。

解析:

最經典的01揹包問題,直接寫就好了,如果這個題沒有這句話”當兩種選取方案有一個數字的下標不一樣,我們就認為是不同的組成方案。 “,那麼這就是個多重揹包問題了.

程式碼:

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

int main()
{
    int n, sum;
    while (cin >> n >> sum) {
        vector<int> arr(n);
        for (int i = 0; i < n; i++)
            cin >> arr[i];
        vector<LL> dp(sum + 1, 0);
        dp[0] = 1;
        for (int i = 0; i < n; i++)
            for (int j = sum; j >= arr[i]; j--)
                dp[j] += dp[j - arr[i]];
        cout << dp[sum] << endl;
    }
    return 0;
}