1. 程式人生 > >美團點評2018春招後臺開發方向程式設計題

美團點評2018春招後臺開發方向程式設計題

美團這次的春招後端方向是兩個程式設計題,沒有考比較難的演算法,如果日積月累刷題還是可以做出來的。

第一題:字串距離

題目:

給出兩個相同長度的由字元 ab 構成的字串,定義它們的距離為對應位置不同的字元的數量。如串”aab”與串”aba”的距離為 2;串”ba”與串”aa”的距離為 1;串”baa”和串”baa”的距離為 0。下面給出兩個字串 ST,其中 S 的長度不小於 T 的長度。我們用|S|代表 S 的長度,|T|代表 T 的長度,那麼在 S 中一共有|S|-|T|+1 個與T長度相同的子串,現在你需要計算 T 串與這些|S|-|T|+1 個子串的距離的和。

輸入描述:

第一行包含一個字串 S。第二行包含一個字串 TST 均由字元 ab 組成,1 ≤ |T| ≤ |S| ≤105

輸出描述:

輸出對應的答案。

樣例:

in:
aab
aba
out:
2
in:
aaabb
bab
out:
5

解析:

如果理論上是會超時的(但是好像有人暴力JAVA過了),正解依然還是要利用之前的結果,避免重複計算;

如果這個題死盯著字串弄是沒有思路的,但是如果你盯著T中的每一個字元看,就有思路了 ;

對於T中的每一個字元,看清楚它會和S中的哪些字母去比較,然後計算一下每一個字元對答案的貢獻

就行了,看下圖:

這裡寫圖片描述

T中0位置的字元和S中橙色的字元比較,……看圖應該就明白了。

時間複雜度:O(n)

這題題中給出了只有ab兩種字母,那有其他字母該怎麼搞呢,其實一樣的,只不過把程式碼中的a, b變數用一個長度為26的陣列代替就好了。具體的看看程式碼。

程式碼:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (string S, T; cin >> S >> T; ) {
        int a = 0, b = 0;
        int
lens = S.size(), lent = T.size(); for (int i = 0; i < lens - lent + 1; i++) a += S[i] == 'a', b += S[i] == 'b'; int ans = 0; for (int i = 0; i + lens - lent < lens; i++) { ans += T[i] == 'a' ? b : a; S[i] == 'a' ? --a : --b; S[i + lens - lent + 1] == 'a' ? ++a : ++b; } cout << ans << endl; } return 0; }

有其他字母的程式碼寫法:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (string S, T; cin >> S >> T; ) {
        int cnt[26] = {0};
        int lens = S.size(), lent = T.size();
        for (int i = 0; i < lens - lent + 1; i++)
            ++cnt[S[i] - 'a'];
        int ans = 0;
        for (int i = 0; i + lens - lent < lens; i++) {
            ans += lens - lent + 1 - cnt[T[i] - 'a'];
            --cnt[S[i] - 'a'];
            ++cnt[S[i + lens - lent + 1] - 'a'];
        }
        cout << ans << endl;
    }
    return 0;
}

第二題:數字字元

題目:

在十進位制表示中,任意一個正整數都可以用字元‘0’-‘9’表示出來。但是當‘0’-‘9’這些字元每種字元的數量有限時,可能有些正整數就無法表示出來了。比如你有兩個‘1’,一個‘2’ ,那麼你能表示出 11,12,121 等等,但是無法表示出 10,122,200 等數。
 
現在你手上擁有一些字元,它們都是‘0’-‘9’的字元。你可以選出其中一些字元然後將它們組合成一個數字,那麼你所無法組成的最小的正整數是多少?

輸入描述:

第一行包含一個由字元’0’-‘9’組成的字串,表示你可以使用的字元。1 ≤ 字串長度 ≤ 1000

輸出描述:

輸出你所無法組成的最小正整數。

樣例:

in:
55
out:
1
in:
123456789
out:
10

解析:

很直觀的思路,首先想想如果暴力該怎麼搞,是不是要從1開始往上列舉。那麼這題的思路差不多,從十進位制位數開始列舉;

先不要看0,0這個字元待會再說,先來看看給出的這些字元能不能湊出一位數,能不能湊出一位數就看看1 - 9是不是都有,如果都有,那麼就可以;然後看看能不能湊出兩位數,如果列舉到了兩位數,那麼就說明1 - 9這些數字的個數大於等於1,什麼時候會出現湊不出來的情況呢,對了,就是需要兩個一樣的數字時,比如1 - 9這些數字的個數都為1,你就絕對湊不出11,對吧;然後來看三位數,後面其實是一樣的了,如果只有兩個1,是湊不出111的,但是112129這些數字都是可以的,因為1 - 9這列舉三位數時就保證的這些字元的個數大於等於2……依次類推就可以了;

等等,好像還有0沒有考慮,那麼現在考慮一下。要湊最小三位數100,最少需要兩個0,少了就不行,那麼只有10的情況,能湊出來的最小的數就是10

想到這一步這個題就解決了啊,先統計1 - 9的個數,然後找出裡面的最小值,最小值表示這些數字至少能湊出幾位數(這裡還沒有考慮字元0),然後看下0字元的個數是不是大於等於最小值減一,這裡舉個例子說明後面的步驟,比如1 - 9每個字母都有3個,03個,111110000都是不可以湊出來的,答案就是1111;比如1 - 9每個字母都有3個,0只有2個,那麼11111000都是不可以湊出來的,答案就是1000

程式碼:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    for (string str; cin >> str; ) {
        vector<int> used(10, 0);
        int digit = -1, theMin = 0x3f3f3f3f;
        for (auto it = str.begin(); it != str.end(); ++it)
            ++used[*it - '0'];
        for (int i = 1; i < 10; i++)
            if (theMin > used[i])
                theMin = used[i], digit = i;
        if (used[0] + 1 <= theMin)
            cout << "1" + string(used[0] + 1, '0') << endl;
        else
            cout << string(theMin + 1, digit + '0') << endl;
    }
    return 0;
}