Skip to content

第 328 场周赛

比赛链接

Date: 2023-01-15

A 数组元素和与数字和的绝对差

Python 快乐题

class Solution {
public:
    int differenceOfSum(vector<int>& nums) {
        int s = accumulate(nums.begin(), nums.end(), 0);
        int t = 0;
        for (auto x : nums) {
            for (auto c : to_string(x)) {
                t += c - '0';
            }
        }
        return abs(s - t);
    }
};
1
2
3
4
5
class Solution:
    def differenceOfSum(self, nums: List[int]) -> int:
        s = sum(nums)
        t = sum(sum(map(int, list(str(num)))) for num in nums)
        return abs(s - t)

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(1)\)

B 子矩阵元素加 1

二维前缀和,容斥原理

class Solution {
public:
    vector<vector<int>> rangeAddQueries(int n, vector<vector<int>>& queries) {
        vector<vector<int>> s(n, vector<int>(n));
        for (auto v : queries) {
            s[v[0]][v[1]]++;
            if (v[3] + 1 < n) s[v[0]][v[3] + 1]--;
            if (v[2] + 1 < n) s[v[2] + 1][v[1]]--;
            if (v[2] + 1 < n && v[3] + 1 < n) s[v[2] + 1][v[3] + 1]++;
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                if (i > 0) s[i][j] += s[i - 1][j];
                if (j > 0) s[i][j] += s[i][j - 1];
                if (i > 0 && j > 0) s[i][j] -= s[i - 1][j - 1];
            }
        }
        return s;
    }
};
class Solution:
    def rangeAddQueries(self, n: int, queries: List[List[int]]) -> List[List[int]]:
        s = [[0] * n for _ in range(n)]
        for r1, c1, r2, c2 in queries:
            s[r1][c1] += 1
            if r2 + 1 < n:
                s[r2 + 1][c1] -= 1
            if c2 + 1 < n:
                s[r1][c2 + 1] -= 1
            if r2 + 1 < n and c2 + 1 < n:
                s[r2 + 1][c2 + 1] += 1

        for i in range(n):
            for j in range(n):
                if i > 0:
                    s[i][j] += s[i - 1][j]
                if j > 0:
                    s[i][j] += s[i][j - 1]
                if i > 0 and j > 0:
                    s[i][j] -= s[i - 1][j - 1]
        return s

复杂度分析

  • 时间复杂度:\(O(n^2)\)
  • 空间复杂度:\(O(n^2)\)

C 统计好子数组的数目

如果子数组 \([l, r]\) 是一个好子数组,那么对于所有的 \(r' \ge r\) , \([l, r']\) 都是好子数组。

所以,可以使用双指针(或者说是滑动窗口)来解决本题,对于每个 \(l\),求出最小的 \(r\) 使得 \([l, r]\) 是好子数组即可。过程中维护一个哈希表,记录区间内每种数字出现的次数,动态的维护 \((i, j), i<j, \textit{arr}[i]=\textit{arr}[j]\) 的个数。

class Solution {
public:
    using ll = long long;
    long long countGood(vector<int>& nums, int k) {
        ll res = 0;
        ll sum = 0;
        unordered_map<int, int> mp;
        auto update = [&](int x, int cnt) {
            sum -= 1ll * mp[x] * (mp[x] - 1) / 2;
            mp[x] += cnt;
            sum += 1ll * mp[x] * (mp[x] - 1) / 2;
        };
        for (int i = 0, j = 0; i < nums.size(); i++) {
            while (j < nums.size() && sum < k) {
                update(nums[j], 1);
                j++;
            }
            if (sum >= k) {
                res += nums.size() - j + 1;
            }
            update(nums[i], -1);
        }
        return res;
    }
};
class Solution:
    def isItPossible(self, word1: str, word2: str) -> bool:
        h1, h2 = Counter(word1), Counter(word2)
        l1, l2 = len(h1), len(h2)
        for x in h1:
            for y in h2:
                if x == y:
                    if l1 == l2:
                        return True
                    continue
                # 计算交换操作之后的种类数
                nl1 = l1 - 1 if h1[x] == 1 else l1
                nl2 = l2 - 1 if h2[y] == 1 else l2
                nl1 = nl1 + 1 if h1[y] == 0 else nl1
                nl2 = nl2 + 1 if h2[x] == 0 else nl2
                if nl1 == nl2:
                    return True
        return False

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)

D 最大价值和与最小价值和的差值

首先,树中最远的两点距离被称为树的直径。我们可以用两次 BFS 来求出它。

  1. 首先随便选一个点(比如 \(0\))进行 BFS,结束后找到距离起点最远的点,把它设为 \(s\)
  2. 然后从 \(s\) 开始 BFS,结束后找到距离 \(s\) 最远的点,把它设为 \(t\)

此时,\(s\)\(t\) 的距离就是树的直径,是整个树中两点配对距离最远的一对点。

但是最终的答案并不一定是以 \(s\) 或者 \(t\) 为根。例如下图中,\(1\)\(5\) 是直径,但是答案是 \(7\)\(5\)

所以,我们应该求出从 \(s\) 以及从 \(t\) 出发到达所有点的距离。然后遍历所有点,枚举以它为根时的答案。这样做的正确性在于,在树中距离每个点最远的点不是 \(s\) 就一定是 \(t\)

class Solution {
public:
    using ll = long long;
    using PII = pair<int, int>;
    long long maxOutput(int n, vector<vector<int>>& edges, vector<int>& price) {
        vector<vector<int>> g(n);
        for (auto v : edges) {
            g[v[0]].push_back(v[1]);
            g[v[1]].push_back(v[0]);
        }
        vector<ll> ds(n), dt(n);
        auto bfs = [&](int s, vector<ll>& d) -> int {
            vector<ll> v(n);
            d[s] = price[s];
            queue<int> q;
            q.push(s);
            v[s] = 1;
            int rt = -1;
            while (q.size()) {
                auto x = q.front(); q.pop();
                if (rt == -1 || d[rt] < d[x]) {
                    rt = x;
                }
                for (auto y : g[x]) {
                    if (v[y]) continue;
                    d[y] = d[x] + price[y];
                    q.push(y);
                    v[y] = 1;
                }
            }
            return rt;
        };
        auto s = bfs(0, ds);
        auto t = bfs(s, ds);
        bfs(t, dt);
        ll res = 0;
        for (int i = 0; i < n; i++) {
            res = max(res, 1ll * max(ds[i], dt[i]) - 1ll * price[i]);
        }
        return res;
    }
};

复杂度分析

  • 时间复杂度:\(O(n)\)
  • 空间复杂度:\(O(n)\)
本文访问