【每日算法Day 100】字節跳動 AI Lab 面試編程題(三道)

今天連着面了兩次字節跳動,勉強撐到了明天三面。一共三道編程題,做的很爛,這裏分享一下。

第一題

給出一條長度爲 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 位置。

最終的時間複雜度是 O(n \log n + n \log k) ,可以直接看作 O(n \log n)

最優解:

最優解當時沒想出來,是用單調棧。維護一個遞增的單調棧,我們的目標是保留 k 個字符,也就是刪除 n-k 個字符。

那麼如果棧頂元素大於當前遍歷元素,並且還沒刪夠 n-k 個,就出棧,當作刪除了一個元素。否則的話如果刪夠了,不管大小關係統統入棧,因爲你沒法刪了。

最後全遍歷完了,如果還沒刪夠,那就繼續出棧,直到刪夠爲止。最後把棧裏的字符拼接成一個字符串就是答案了。

時間複雜度是 O(n) 的。

代碼

        #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;
}

      

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章