美團點評2018春招後臺開發方向程式設計題
美團這次的春招後端方向是兩個程式設計題,沒有考比較難的演算法,如果日積月累刷題還是可以做出來的。
第一題:字串距離
題目:
給出兩個相同長度的由字元
a
和b
構成的字串,定義它們的距離為對應位置不同的字元的數量。如串”aab”
與串”aba”
的距離為2
;串”ba”
與串”aa”
的距離為1
;串”baa”
和串”baa”
的距離為0
。下面給出兩個字串S
與T
,其中S
的長度不小於T
的長度。我們用|S|
代表S
的長度,|T|
代表T
的長度,那麼在S
中一共有|S|-|T|+1
個與T
長度相同的子串,現在你需要計算T
串與這些|S|-|T|+1
個子串的距離的和。
輸入描述:
第一行包含一個字串
S
。第二行包含一個字串T
。S
和T
均由字元a
和b
組成,1 ≤ |T| ≤ |S| ≤105
。
輸出描述:
輸出對應的答案。
樣例:
in: aab aba out: 2
in: aaabb bab out: 5
解析:
如果理論上是會超時的(但是好像有人暴力JAVA過了),正解依然還是要利用之前的結果,避免重複計算;
如果這個題死盯著字串弄是沒有思路的,但是如果你盯著T
中的每一個字元看,就有思路了 ;
對於T
中的每一個字元,看清楚它會和S
中的哪些字母去比較,然後計算一下每一個字元對答案的貢獻
T
中0位置的字元和S
中橙色的字元比較,……看圖應該就明白了。
時間複雜度:。
這題題中給出了只有a
,b
兩種字母,那有其他字母該怎麼搞呢,其實一樣的,只不過把程式碼中的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
的,但是112
,129
這些數字都是可以的,因為1 - 9
這列舉三位數時就保證的這些字元的個數大於等於2……依次類推就可以了;
等等,好像還有0沒有考慮,那麼現在考慮一下。要湊最小三位數100
,最少需要兩個0
,少了就不行,那麼只有1
個0
的情況,能湊出來的最小的數就是10
;
想到這一步這個題就解決了啊,先統計1 - 9
的個數,然後找出裡面的最小值,最小值表示這些數字至少能湊出幾位數(這裡還沒有考慮字元0
),然後看下0
字元的個數是不是大於等於最小值減一,這裡舉個例子說明後面的步驟,比如1 - 9
每個字母都有3個,0
有3
個,1111
和10000
都是不可以湊出來的,答案就是1111
;比如1 - 9
每個字母都有3個,0
只有2
個,那麼1111
和1000
都是不可以湊出來的,答案就是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;
}