第 232 场周赛
Problem A - 仅执行一次字符串交换能否使两个字符串相等
一次遍历即可。统计出所有不同的位置:
- 如果全都相同:可以将任意位置的字符与其自身进行一次交换。 
- 如果只有一处不同,或超过两处不同:无法通过一次交换使两个字符串相等。 
- 如果恰好有两处不同:检查交换这个两个位置是否能使这两个字符串相等。 
- 时间复杂度。 
- 空间复杂度。 
参考代码(C++)
class Solution {
public:
    bool areAlmostEqual(string s1, string s2) {
        vector<int> diff;
        for (int i = 0; i < s1.size(); ++i)
            if (s1[i] != s2[i]) {
                diff.emplace_back(i);
                if (diff.size() > 2)
                    return false;
            }
        if (diff.empty())
            return true;
        if (diff.size() != 2)
            return false;
        return s1[diff[0]] == s2[diff[1]] && s1[diff[1]] == s2[diff[0]];
    }
};
Problem B - 找出星型图的中心节点
因为,所以星型图中有且只有中心节点的度数大于,因此只要统计节点的度数即可。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
    int findCenter(vector<vector<int>>& edges) {
        unordered_map<int, int> cnt;
        for (auto &edge : edges) {
            cnt[edge[0]]++;
            if (cnt[edge[0]] > 1)
                return edge[0];
            cnt[edge[1]]++;
            if (cnt[edge[1]] > 1)
                return edge[1];
        }
        return 0;
    }
};
Problem C - 最大平均通过率
在大根堆中存储每个班级中增加一个通过学生后通过率的提升量,每次贪心地将学生安排到通过率提升最大的班级中即可。
- 时间复杂度。其中为班级数量,为额外的学生数量。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
    double maxAverageRatio(vector<vector<int>>& classes, int extraStudents) {
        int n = classes.size();
        vector<int> total(n), pass(n);
        for (int i = 0; i < n; ++i)
            pass[i] = classes[i][0], total[i] = classes[i][1];
        
        auto calc = [&](int idx) {
            double original = (double) pass[idx] / (double) total[idx];
            double update = (double) (pass[idx] + 1) / (double) (total[idx] + 1);  
            return update - original;
        };
        
        priority_queue<pair<double, int>> pq;
        for (int i = 0; i < n; ++i) {
            pq.emplace(calc(i), i);
        }
        
        while (extraStudents) {
            extraStudents--;
            auto [delta, idx] = pq.top();
            pq.pop();
            pass[idx]++;
            total[idx]++;
            pq.emplace(calc(idx), idx);
        }
        
        double sum = 0.0;
        for (int i = 0; i < n; ++i)
            sum += (double) pass[i] / (double) total[i];
        
        return sum / n;
    }
};
Problem D - 好子数组的最大分数
使用单调栈:
- 从左到右遍历,找到每个数右边第一个比它小的数的位置;
- 从右到左遍历,找到每个数左边第一个比它小的数的位置。
利用这两个值,可以得到以某一个数为最小值的最大区间范围。检查所有包含了位置的区间,就可以得到所要求的的最大分数。
- 时间复杂度。
- 空间复杂度。
参考代码(C++)
class Solution {
public:
    int maximumScore(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> left(n, -1), right(n, n);
        stack<int> st;
        for (int i = 0; i < n; ++i) {
            while (!st.empty() && nums[st.top()] > nums[i]) {
                right[st.top()] = i;
                st.pop();
            }
            st.push(i);
        }
        st = stack<int>();
        for (int i = n - 1; i >= 0; --i) {
            while (!st.empty() && nums[st.top()] > nums[i]) {
                left[st.top()] = i;
                st.pop();
            }
            st.push(i);
        }
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int l = left[i] + 1, r = right[i] - 1;
            if (l <= k && r >= k)
                ans = max(ans, (r - l + 1) * nums[i]);
        }
        return ans;
    }
};