今天連着面了兩次字節跳動,勉強撐到了明天三面。一共三道編程題,做的很爛,這裏分享一下。
第一題
給出一條長度爲 L
的線段,除了頭和尾兩個點以外,上面還有 n
個整數點,需要在上面再放 k
個新的點,使得相鄰的兩個點之間的最大距離最小,求這個最小的距離。
題解
我當時太緊張了,真是腦抽了,還想着弄個優先隊列,劃分最大的,然後丟進去,再劃分最大的,但是是錯的。
正確解法小姐姐走了我纔想起來,二分答案 m
,然後掃描一遍判斷將每一段劃分成小於等於 m
的一共需要多少次。如果次數大於 k
,說明 m
太短了,否則說明 m
太長了。
代碼
#include <bits/stdc++.h>
using namespace std;
int main() {
int L, n, k;
scanf("%d%d%d", &L, &n, &k);
vector<int> a(n+2, 0);
a[0] = 1;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
a[n+1] = L;
int l = 1, r = L-1;
while (l < r) {
int m = l + (r - l) / 2;
int cnt = 0;
for (int i = 1; i <= n+1; ++i) {
cnt += (a[i] - a[i-1] - 1) / m;
}
if (cnt > k) l = m + 1;
else r = m;
}
cout << l << endl;
return 0;
}
第二題
給出一個數組 A
,找到最大的 A[i] - A[j]
,要求 i > j
。
題解
這題很簡單,直接遍歷每個 A[i]
,維護它前面最小的那個數 minn
,然後求出最大的 A[i] - minn
就行了。
代碼
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
scanf("%d", &n);
vector<int> a(n, 0);
for (int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
}
int minn = a[0], res = INT_MIN;
for (int i = 1; i < n; ++i) {
res = max(res, a[i]-minn);
minn = min(minn, a[i]);
}
cout << res << endl;
}
第三題
給定一個字符串,對該字符串進行刪除操作,保留 k
個字符且相對位置不變,使字典序最小。
題解
這題也腦抽了,想了一堆方法,dp
複雜度太高,線段樹太麻煩,最後用 map
勉強寫了一下。
主要思想是這樣的,最後要保留 k
個字符,那麼第一個字符只能在下標 0 ~ n-k
中尋找,那肯定找最小的啊,如果有多個就找最前面那個,把它的位置記爲 pos
。
然後第二個字符肯定得在下標 pos ~ n-k+1
中尋找,還是一樣的思路,找到以後更新 pos
位置,依次找下去找到 k
個爲止。
所以我就利用了 map
的特性,把尋找窗口內的字符個數做一下統計,然後取出 map
中的第一個字符就是字典序最小的了,次數減一,如果減到 0 了就刪除掉。
然後從 pos
位置開始遍歷,直到第一個等於你剛剛取出的字符爲止,更新 pos
位置。
最終的時間複雜度是 ,可以直接看作 。
最優解:
最優解當時沒想出來,是用單調棧。維護一個遞增的單調棧,我們的目標是保留 k
個字符,也就是刪除 n-k
個字符。
那麼如果棧頂元素大於當前遍歷元素,並且還沒刪夠 n-k
個,就出棧,當作刪除了一個元素。否則的話如果刪夠了,不管大小關係統統入棧,因爲你沒法刪了。
最後全遍歷完了,如果還沒刪夠,那就繼續出棧,直到刪夠爲止。最後把棧裏的字符拼接成一個字符串就是答案了。
時間複雜度是 的。
代碼
#include <bits/stdc++.h>
using namespace std;
string f(string s, int k) {
int n = s.size();
map<char, int> mp;
for (int i = 0; i <= n-k; ++i) {
mp[s[i]]++;
}
string res = "";
int pos = 0;
for (int i = k; i >= 1; --i) {
char c = mp.begin()->first;
res += c;
for (int j = pos; j <= n-i; ++j) {
mp[s[j]]--;
if (!mp[s[j]]) mp.erase(s[j]);
if (s[j] == c) {
pos = j + 1;
break;
}
}
if (i == 1) break;
mp[s[n-i+1]]++;
}
return res;
}
int main() {
string s;
int k;
cin >> s >> k;
cout << f(s, k) << endl;
}
最優解:
#include <bits/stdc++.h>
using namespace std;
string f(string s, int k) {
int n = s.size();
k = n - k;
stack<char> st;
for (int i = 0; i < n; ++i) {
while (!st.empty() && st.top() > s[i] && k) {
st.pop();
k--;
}
st.push(s[i]);
}
string res = "";
while (!st.empty()) {
if (k) k--;
else res += st.top();
st.pop();
}
reverse(res.begin(), res.end());
return res;
}
int main() {
string s;
int k;
cin >> s >> k;
cout << f(s, k) << endl;
}