第 354 场LeetCode周赛

A 特殊元素平方和

第 354 场LeetCode周赛_第1张图片

模拟

class Solution {
public:
    int sumOfSquares(vector<int> &nums) {
        int res = 0;
        int n = nums.size();
        for (int i = 0; i < n; i++)
            if (n % (i + 1) == 0)
                res += nums[i] * nums[i];
        return res;
    }
};

B 数组的最大美丽值

第 354 场LeetCode周赛_第2张图片
第 354 场LeetCode周赛_第3张图片

差分数组: n u m s [ i ] nums[i] nums[i]可以变为 [ n u m s [ i ] − k , n u m s [ i ] + k ] [nums[i] - k, nums[i] + k] [nums[i]k,nums[i]+k]内的数, 所有可以用差分数组将这段区间+1, 遍历数组执行区间加之后求差分数组前缀和的最大值, 注意为避免下标为负数可以将下标添加一个偏移量.

class Solution {
public:
    int maximumBeauty(vector<int> &nums, int k) {
        int mx = 0, mn = INT32_MAX;//nums中的最小值和最大值
        for (auto x: nums) {
            mx = max(mx, x);
            mn = min(mn, x);
        }
        int c = mn - k;//下标偏移量
        int N = mx + k + 1 - (mn - k) + 2;
        int d[N];
        memset(d, 0, sizeof(d));
        for (auto x: nums) {
            d[x - k - c]++;
            d[x + k - c + 1]--;
        }
        int res = 0;
        for (int i = 0, cur = 0; i < N; i++) {
            cur += d[i];
            res = max(res, cur);
        }
        return res;
    }
};

C 合法分割的最小下标

第 354 场LeetCode周赛_第4张图片
第 354 场LeetCode周赛_第5张图片

模拟: 一个合法分割两边的支配元素必等于原数组的支配元素, 所有升序枚举 i i i, 记录两边支配元素的计数, 判断是否满足条件

class Solution {
public:
    int minimumIndex(vector<int> &nums) {
        map<int, int> cnt;
        for (auto x: nums)
            cnt[x]++;
        int val, mx = 0;//支配元素为val, 其出现次数为mx
        for (auto &[k, v]: cnt)
            if (v > mx) {
                val = k;
                mx = v;
            }
        for (int i = 0, cur = 0, n = nums.size(); i < n - 1; i++) {
            if (nums[i] == val)
                cur++;
            if (cur * 2 > i + 1 && (mx - cur) * 2 > n - i - 1)//是一个合法分割
                return i;
        }
        return -1;
    }
};

D 最长合法子字符串的长度

第 354 场LeetCode周赛_第6张图片

线段树: 定义 r [ i ] r[i] r[i]表示以 w o r d [ i ] word[i] word[i]为左端点的没有出现在 f o r b i d d e n forbidden forbidden中的最长字符串长度为 r [ i ] − i + 1 r[i]-i+1 r[i]i+1. 因为 f o r b i d d e n forbidden forbidden中字符串长度不超过10, 所有可以先用集合存一下 f o r b i d d e n forbidden forbidden的串, 然后遍历 i i i计算出 r [ i ] r[i] r[i]. 考虑以 i i i为左端点的字串, 其最长的合法子字符串长度为 m i n { r [ k ]    ∣    i ≤ k ≤ r [ i ] } − i + 1 min\{r[k] \; |\; i\le k \le r[i] \}-i+1 min{r[k]ikr[i]}i+1, 用线段树求区间最小值.

typedef long long ll;
//线段树模板
struct SegmentTree {
    ll tl;
    ll tr;
    ll s;
    ll mark;
    int lazy;
};
vector<SegmentTree> st;

inline void push_down(ll index) {
    st[index << 1].lazy = 1;
    st[index << 1 | 1].lazy = 1;
    st[index << 1].mark += st[index].mark;
    st[index << 1 | 1].mark += st[index].mark;
    st[index << 1].s += st[index].mark;
    st[index << 1 | 1].s += st[index].mark;

    st[index].lazy = 0;
    st[index].mark = 0;
}

inline void push_up(ll index) {
    st[index].s = min(st[index << 1].s, st[index << 1 | 1].s);
}

void build(ll l, ll r, vector<int> &li, ll index = 1) {//初始化
    st[index].tl = l;
    st[index].tr = r;
    st[index].lazy = 0;
    st[index].mark = 0;
    if (l == r) {
        st[index].s = li[l - 1];
    } else {
        ll mid = (l + r) >> 1;
        build(l, mid, li, index << 1);
        build(mid + 1, r, li, index << 1 | 1);
        push_up(index);
    }
}


ll query(ll l, ll r, ll index = 1) {//查询区间[l,r]上的最小值
    if (l <= st[index].tl and st[index].tr <= r) {
        return st[index].s;
    } else {
        if (st[index].lazy)
            push_down(index);
        if (r <= st[index << 1].tr)
            return query(l, r, index << 1);
        else if (l > st[index << 1].tr)
            return query(l, r, index << 1 | 1);
        return min(query(l, r, index << 1), query(l, r, index << 1 | 1));
    }
}

class Solution {
public:
    int longestValidSubstring(string word, vector<string> &forbidden) {
        set<string> vis[11];
        for (auto &si: forbidden)//按串的长度分组
            vis[si.size()].insert(si);
        int n = word.size();
        vector<int> r(n, n - 1);
        for (int i = 0; i < n; i++) {//计算r[i]
            string t;
            for (int j = i; j < n && t.size() < 10; j++) {
                t.push_back(word[j]);
                if (vis[t.size()].count(t)) {
                    r[i] = j - 1;//
                    break;
                }
            }
        }
        st = vector<SegmentTree>(4 * n + 5);
        build(1, n, r);// 建树, 树中下标从1开始
        int res = 0;
        for (int i = 0; i < n; i++)//枚举左端点
            if (i <= r[i])
                res = max(res, (int) query(i + 1, r[i] + 1) - i + 1);
        return res;
    }
};

你可能感兴趣的:(LeetCode,leetcode,算法,职场和发展,线段树,差分数组)