1. 程式人生 > 其它 >單週賽 253 題解

單週賽 253 題解

知識點:字串比較,大根堆,貪心,最長上升子序列,二分優化

知識點:字串比較,大根堆,貪心,最長上升子序列,二分優化

檢查字串是否為陣列字首

給定一個字串 \(s\),給定一個字典 \(w\),如果 \(w\) 中前 \(k\) 個字串可以構成 \(s\),返回 \(true\),否則返回 \(false\),其中 \(1\leq k\leq w.size\)

題解

模擬

// cpp
class Solution {
public:
    bool isPrefixString(string s, vector<string>& words) {
        string temp;
        for (int i = 0; i < words.size(); ++i) {
            temp += words[i];
            if (s == temp) return 1;
        }
        return 0;
    }
};
// go
func isPrefixString(s string, w []string) bool {
    var temp string 
    for _, i := range w {
        temp += i
        if s == temp {
            return true
        }
    }
    return false
}

移除石子使總數最小

給定長 \(n\) 的陣列 \(a\),給定 \(k\),執行 \(k\) 次操作,每次把 \(a_{i}\) 減去 \(\lfloor\frac{a_{i}}{2}\rfloor\)

,返回操作後 \(a\) 的陣列和的可能的最小值

題解

貪心,每次對最大的 \(a_{i}\) 操作即可,使用優先佇列維護,時間複雜度 \(O(n\log n)\)

// cpp
class Solution {
public:
    int minStoneSum(vector<int>& piles, int k) {
        priority_queue<int> pq;
        for (auto &i: piles) pq.push(i);
        while (k--) {
            int top = pq.top(); pq.pop();
            pq.push(top - top / 2);
        }
        int ans = 0;
        while (!pq.empty()) {
            ans += pq.top(); pq.pop();
        }
        return ans;
    }
};

使字串平衡的最小交換次數

給定 [] 組成的字串,你可以交換任意兩個括號,使得整體括號匹配,返回最小的交換數

保證左右括號數相等

題解

找規律,對於題設中的字串,一定可以抽象成 ]]]]][[[[[ 的形式,設共有 \(n\) 對,那麼答案即為 \(\lceil\frac{n}{2}\rceil\)

// cpp
class Solution {
public:
    int minSwaps(string s) {
        int l = 0, r = 0;
        for (auto &i: s) {
            if (i == '[') l++;
            else {
                if (l) l--;
                else r++;
            }
        }
        return (r + 1) / 2;
    }
};
// go
func minSwaps(s string) int {
    l := 0
    r := 0
    for _, i := range(s) {
        if i == '[' {
            l++
        } else {
            if l > 0 {
                l--
            } else {
                r++
            }
        }
    }
    return (r + 1) / 2
}

找出到每個位置為止最長的有效障礙賽跑路線

給定長為 \(n\) 的陣列 \(a\),找到以每個位置 \(i\) 結尾的最長不降子序列的長度,以陣列形式返回

資料規定

\(1\leq n\leq 10^5\)

題解

使用 \(LIS\) 的二分解法

具體來講,設 \(dp[i]\) 表示長為 \(i + 1\) 的最長不降子序列的最後一個位置的最小值,初始化為 \(inf\)

對於每一個位置 \(i\),可以在 \(dp\) 陣列中二分查詢最後一個小於 \(a[i]\) 的位置,並把 \(a[i]\) 賦值在該位置後面,獲取最長不降子序列的長度只需要用該位置減去陣列頭,維護答案即可

舉個例子,對 a[4] = [1, 2, 3, 2] 進行操作

dp 陣列初始化:
[inf, inf, inf, inf]

處理 a[0] = 1,得到:
[1, inf, inf, inf]

處理 a[1] = 2,得到:
[1, 2, inf, inf]

處理 a[2] = 3,得到:
[1, 2, 3, inf]

處理 a[3] = 2,得到:
[1, 2, 2, inf]
// cpp
class Solution {
public:
    #define inf 0x3f3f3f3f
    vector<int> longestObstacleCourseAtEachPosition(vector<int>& o) {
        int n = o.size();
        vector<int> dp(n + 7), ans(n + 7);
        fill(dp.begin(), dp.end(), inf);
        for (int i = 0; i < n; ++i) {
            int len = upper_bound(dp.begin(), dp.end(), o[i]) - dp.begin() + 1;
            *upper_bound(dp.begin(), dp.end(), o[i]) = o[i];
            ans[i] = len;
        }
        return {ans.begin(), ans.begin() + n};
    }
};