Skip to content

第 437 场周赛

比赛链接

T1 找出长度为 K 的特殊子字符串

直接暴力行不行呢?

class Solution {
public:
    bool hasSpecialSubstring(string s, int k) {
        int n = s.size();
        for (int i = 0; i + k <= n; i++) {
            if (i > 0 && s[i] == s[i - 1]) {
                continue;
            }
            if (i + k < n && s[i + k - 1] == s[i + k]) {
                continue;
            }
            bool f = true;
            for (int j = i + 1; j < i + k; j++) {
                if (s[i] != s[j]) {
                    f = false;
                    break;
                }
            }
            if (f) {
                return true;
            }
        }
        return false;
    }
};

T2 吃披萨

此题略难,wa 了三次。

每四个一组,共 \(n/4\) 组,那么会有 \(x\) 组取 \(Z\)\(y\) 组取 \(Y\)。其中 \(x + y == n / 4\),并且 \(y = n / 8\)

那么,我们的贪心准则就是取最大的 \(x\) 个元素做 \(Z\),然后剩下的最大和次大去凑一组,次大的会贡献给答案。

class Solution {
public:
    long long maxWeight(vector<int>& p) {
        using ll = long long;
        sort(p.begin(), p.end());
        int n = p.size();
        int l = 0, r = n - 1;
        int cnt = n / 4;
        ll res = 0;
        for (int i = 0; i < cnt / 2 + (cnt % 2); i++) {
            res += p[r];
            r--;
            l += 3;
        }
        for (int i = 0; i < cnt / 2; i++) {
            r--;
            res += p[r];
            r--;
            l += 2;
        }
        return res;
    }
};

T3 选择 K 个互不重叠的特殊子字符串

这题在场上可是难到我了,emmm。

题目要求分出 K 段不重叠的子串,并且每个子串内部的字符都是独享的,字符串的其他部分并没有这些字符。

因此,如果我们想要有 a 字符,就需要把所有的 a 字符囊括进来,这样一来,如果中间还夹杂着别的字符,那也需要把别的字符都囊括进来。这个过程会扩张若干次。

而每次扩张的复杂度其实并不高,假设每次扫描 26 种字符,只扩张一次,使用二分去检查当前扫描字符是否需要扩张,那么复杂度就是 \(26\log n\),最多扩张 \(26\) 次,因此总体复杂度就是 \(26^2\log n\)

我们对所有字符都扩张一次,那么复杂度是 \(26^3\log n\)

然后,得到的这些区间,每个单拎出来都是特殊子字符串。我们要找到他们的最大不重叠集合。这个也是老题,435. 无重叠区间

当然,我们这个题中不会有两个区间有交叉,但可能会有覆盖。不过这个情形可以忽略,一并当做普通题目来做。

class Solution {
public:
    bool maxSubstringLength(string s, int k) {
        if (k == 0) return true;
        int n = s.size();
        unordered_map<char, vector<int>> b;
        for (int i = 0; i < s.size(); i++) {
            b[s[i]].push_back(i);
        }
        vector<pair<int, int>> v;
        for (auto &[c, cv] : b) {
            int l = cv.front(), r = cv.back();
            bool expond = true;
            while (expond) {
                expond = false;
                for (auto &[t, tv] : b) {
                    if (t == c) continue;
                    int cnt = upper_bound(tv.begin(), tv.end(), r) - lower_bound(tv.begin(), tv.end(), l);
                    if (cnt != 0 && cnt != tv.size()) {
                        expond = true;
                        l = min(l, tv.front());
                        r = max(r, tv.back());
                    }
                }
            }
            if (l != 0 || r != n - 1) {
                // cout << l << ' ' << r << endl;
                v.push_back(make_pair(l, r));
            }
        }
        sort(v.begin(), v.end(), [](const pair<int, int> &lth, const pair<int, int> &rth) {
            return lth.second < rth.second;
        });
        int cnt = 0;
        int R = -1;
        for (auto p : v) {
            if (p.first <= R) {
                R = max(R, p.second);
            } else {
                R = p.second;
                cout << p.first << ' ' << p.second << ' ' << cnt << endl;
                cnt++;
            }
        }
        return k <= cnt;
    }
};

T4 最长 V 形对角线段的长度

这个题,第一眼下去就是 DP,但是怎么 DP 呢?

我想的是每个位置存当前方向,以及是否拐弯这两个状态。但这样下来就有 \(500 * 500 * 8\) 个状态需要存。

代码写起来参数会比较乱。后来看到一种解法,我们可以外层固定初始方向,这样可以节省 3 倍的空间。

是的,因为不同初始方向之间的问题是相互独立的。

int d[505][505][2];
class Solution {
public:
    static constexpr int inf = 0x3f3f3f3f;
    int lenOfVDiagonal(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        int dir[4][2] = {{-1, 1}, {1, 1}, {1, -1}, {-1, -1}};

        auto check = [&](int x, int y, int nx, int ny) {
            if (x < 0 || x >= n || y < 0 || y >= m) {
                return false;
            }
            if (grid[x][y] == 0 || grid[x][y] == 1) {
                return grid[nx][ny] == 2;
            } else {
                return grid[nx][ny] == 0;
            }
        };
        int k = 0;
        function<int(int, int, int)> dfs = [&](int i, int j, int t) {
            if (grid[i][j] == 1) {
                return 1;
            }
            int &res = d[i][j][t];
            if (res != -inf) return res;
            if (t == 0) {
                int ri = i - dir[k][0];
                int rj = j - dir[k][1];
                if (check(ri, rj, i, j)) {
                    res = max(res, dfs(ri, rj, t) + 1);
                }
            } else {
                int ri = i - dir[(k + 1) % 4][0];
                int rj = j - dir[(k + 1) % 4][1];
                if (check(ri, rj, i, j)) {
                    res = max(res, dfs(ri, rj, 1) + 1);
                    res = max(res, dfs(ri, rj, 0) + 1);
                }
            }
            return res;
        };
        int res = 0;
        for (k = 0; k < 4; k++) {
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    d[i][j][0] = d[i][j][1] = -inf;
                }
            }
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < m; j++) {
                    res = max(res, dfs(i, j, 0));
                    res = max(res, dfs(i, j, 1));
                }
            }
        }
        return res;
    }
};
本站总访问量 Loading 本站总访客数 Loading