第390场 LeetCode 周赛题解

A 每个字符最多出现两次的最长子字符串

在这里插入图片描述

滑动窗口:枚举窗口的左边界,尽可能右移窗口的右边界。 (当然也可以暴力枚举)

class Solution {
public:
    int maximumLengthSubstring(string s) {
        vector<int> cnt(26);
        int res = 0;
        for (int l = 0, r = -1, n = s.size();; cnt[s[l++] - 'a']--) {
            while (r + 1 < n && cnt[s[r + 1] - 'a'] + 1 <= 2)
                cnt[s[++r] - 'a']++;
            res = max(res, r - l + 1);
            if (r == n - 1)
                break;
        }
        return res;
    }
};

B 执行操作使数据元素之和大于等于 K

在这里插入图片描述

枚举:容易知道存在一种方案:“先通过第一种操作将数组从 [ 1 ] [1] [1] 变为 [ i ] [i] [i] ,再通过第二种操作让数组和不小于 k k k” 可以让操作数最少。枚举 i i i 以计算最小操作数

class Solution {
public:
    int minOperations(int k) {
        int res = INT32_MAX;
        for (int i = 1; i <= k; i++)
            res = min(res, i - 1 + (k - 1) / i);
        return res;
    }
};

C 最高频率的 ID

在这里插入图片描述
在这里插入图片描述

最大堆+哈希:用最大堆维护当前频率最高的ID,用哈希表记录各ID的最新频率

class Solution {
public:
    using ll = long long;

    vector<long long> mostFrequentIDs(vector<int> &nums, vector<int> &freq) {
        priority_queue<pair<ll, int>> heap;//(freq,id)
        unordered_map<int, ll> f;
        vector<ll> res;
        for (int i = 0; i < nums.size(); i++) {
            f[nums[i]] += freq[i];
            heap.emplace(f[nums[i]], nums[i]);
            while (f[heap.top().second] != heap.top().first)
                heap.pop();
            res.push_back(heap.top().first);
        }
        return res;
    }
};

D 最长公共后缀查询

在这里插入图片描述
在这里插入图片描述

字典树:遍历 wordsContainer 中的字符串,并将其按后缀插入字典树,同时更新字典树插入路径上的标记。然后遍历 wordsQuery ,在字典树上查询匹配的最长后缀的标记

class Solution {
public:
    vector<int> stringIndices(vector<string> &wordsContainer, vector<string> &wordsQuery) {
        trie tree;
        for (int i = 0; i < wordsContainer.size(); i++)
            tree.insert(wordsContainer[i], i, wordsContainer[i].size());
        vector<int> res;
        for (auto &q: wordsQuery) 
            res.push_back(tree.find(q));
        return res;
    }

    class trie {//字典树
    public:
        trie *next[26];
        int ind;//标记
        int mn;//wordsContainer[ind]的长度

        trie() {
            for (int i = 0; i < 26; i++)
                next[i] = nullptr;
            ind = -1;
            mn = 0;
        }

        void insert(string &s, int id, int len_i) {
            trie *cur = this;
            if (cur->ind == -1 || cur->mn > len_i) {//公共后缀为空的情况
                cur->ind = id;
                cur->mn = len_i;
            }
            for (auto i = s.rbegin(); i != s.rend(); i++) {
                if (!cur->next[*i - 'a'])
                    cur->next[*i - 'a'] = new trie();
                cur = cur->next[*i - 'a'];
                if (cur->ind == -1 || cur->mn > len_i) {//更新标记
                    cur->ind = id;
                    cur->mn = len_i;
                }
            }
        }

        int find(string &s) {
            trie *cur = this;
            for (auto i = s.rbegin(); i != s.rend(); i++) {
                if (!cur->next[*i - 'a'])
                    break;
                cur = cur->next[*i - 'a'];
            }
            return cur->ind;
        }
    };
};
  • 24
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值