Leetcode 第 380 场周赛题解
- Leetcode 第 380 场周赛题解
- 题目1:3005. 最大频率元素计数
- 思路
- 代码
- 复杂度分析
- 题目2:3006. 找出数组中的美丽下标 I
- 思路
- 代码
- 复杂度分析
- 题目3:3007. 价值和小于等于 K 的最大数字
- 思路
- 代码
- 复杂度分析
- 题目4:3008. 找出数组中的美丽下标 II
- 思路
- 代码
- 复杂度分析
Leetcode 第 380 场周赛题解
题目1:3005. 最大频率元素计数
思路
遍历数组 nums,统计各元素 num 的出现次数,存储在哈希表 cnt 中。
初始化 sum = 0,max_freq = 0。
遍历哈希表 cnt:
- 如果当前 freq > max_freq,则令 max_freq = freq,sum 归 0 后重新加一个 freq(sum = freq)。
- 如果当前 freq = max_freq,则 sum += freq。
答案为 sum。
代码
/** @lc app=leetcode.cn id=3005 lang=cpp** [3005] 最大频率元素计数*/// @lc code=start
class Solution
{
public:int maxFrequencyElements(vector<int> &nums){// 特判if (nums.empty())return 0;unordered_map<int, int> cnt;for (int &num : nums)cnt[num]++;int max_freq = 0, sum = 0;for (auto &[num, freq] : cnt){if (freq > max_freq){max_freq = freq;sum = freq;}else if (freq == max_freq)sum += freq;}return sum;}
};
// @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。
空间复杂度:O(n),其中 n 是数组 nums 的长度。
题目2:3006. 找出数组中的美丽下标 I
思路
用 C++ 标准库中的字符串查找函数,找到 a 和 b 分别在 s 中的起始下标,将符合要求的下标插入答案。
代码
/** @lc app=leetcode.cn id=3006 lang=cpp** [3006] 找出数组中的美丽下标 I*/// @lc code=start
class Solution
{
public:vector<int> beautifulIndices(string s, string a, string b, int k){// 特判if (s.empty() || a.empty() || b.empty() || k <= 0 || k > s.size())return {};if (s.length() < a.length() || s.length() < b.length())return {};int slen = s.size(), alen = a.size(), blen = b.size();vector<int> indices;for (int i = 0; i <= slen - alen; i++){if (s.substr(i, alen) == a){// 注意减小 j 的取值范围int start = max(0, i - k), end = min(slen, i + k);for (int j = start; j <= end; j++)if (s.substr(j, blen) == b){indices.push_back(i);break;}}}return indices;}
};
// @lc code=end
复杂度分析
时间复杂度:O(slen * alen * blen),其中 slen 是字符串 s 的长度,alen 是字符串 a 的长度,blen 是字符串 b 的长度。
空间复杂度:O(1)。
题目3:3007. 价值和小于等于 K 的最大数字
思路
二分答案 + 数位 DP。
题解:三种方法:二分答案+数位 DP/数学公式/逐位构造(Python/Java/C++/Go)
代码
/** @lc app=leetcode.cn id=3007 lang=cpp** [3007] 价值和小于等于 K 的最大数字*/// @lc code=start// 二分查找 + 数位 DPclass Solution
{
public:long long findMaximumNumber(long long k, int x){long long left = 0, right = (k + 1) << x;while (left + 1 < right){long long mid = left + (right - left) / 2;if (countDigitOne(mid, x) <= k)left = mid;elseright = mid;}return left;}// 辅函数 - 计算所有小于等于 num 的非负整数中的价值总和// 一个整数 num 的价值是满足 i % x == 0 且 s[i] 是 1 的 i 的数目long long countDigitOne(long long num, int x){int m = 64 - __builtin_clzll(num);vector<vector<long long>> memo(m, vector<long long>(m + 1, -1));function<long long(int, int, bool)> dfs = [&](int i, int cnt1, bool is_limit) -> long long{if (i < 0)return cnt1;if (!is_limit && memo[i][cnt1] >= 0)return memo[i][cnt1];int up = is_limit ? num >> i & 1 : 1;long long res = 0;for (int d = 0; d <= up; d++) // 枚举要填入的数字 dres += dfs(i - 1, cnt1 + (d == 1 && (i + 1) % x == 0), is_limit && d == up);if (!is_limit)memo[i][cnt1] = res;return res;};return dfs(m - 1, 0, true);}
};
// @lc code=end
复杂度分析
题目4:3008. 找出数组中的美丽下标 II
思路
KMP + 二分查找。
KMP 详解:KMP 算法详解(C++ Version)
题解:两种写法:KMP+二分查找/双指针(Python/Java/C++/Go)
代码
/** @lc app=leetcode.cn id=3008 lang=cpp** [3008] 找出数组中的美丽下标 II*/// @lc code=start// KMP + 二分查找class Solution
{
public:vector<int> beautifulIndices(string s, string a, string b, int k){vector<int> posA = kmp(s, a);vector<int> posB = kmp(s, b);vector<int> ans;// 二分查找// for (int i : posA)// {// auto it = lower_bound(posB.begin(), posB.end(), i);// if (it != posB.end() && *it - i <= k ||// it != posB.begin() && i - *--it <= k)// {// ans.push_back(i);// }// }// 双指针int j = 0, m = posB.size();for (int i : posA){while (j < m && posB[j] < i - k)j++;if (j < m && posB[j] <= i + k)ans.push_back(i);}return ans;}// 辅函数 - KMPvector<int> kmp(string &text, string &pattern){int m = pattern.length();vector<int> nxt = getNxt(pattern);vector<int> res;int tar = 0; // 主串中将要匹配的位置int pos = 0; // 模式串中将要匹配的位置while (tar < text.length()){if (text[tar] == pattern[pos]){// 若两个字符相等,则 tar、pos 各进一步tar++;pos++;}else if (pos != 0){// 失配,如果 pos != 0,则依据 nxt 移动标尺pos = nxt[pos - 1];}else{// pos[0] 失配,标尺右移一位tar++;}// pos 走到了 pattern.length(),匹配成功if (pos == pattern.length()){// 保存主串上的匹配起点res.push_back(tar - pos);// 移动标尺pos = nxt[pos - 1];}}return res;}// 辅函数 - 计算 nxt 数组// vector<int> getNxt(string &pattern)// {// int m = pattern.length();// vector<int> nxt(m, 0);// for (int i = 0; i < m; i++)// {// string sub = pattern.substr(0, i + 1);// for (int j = sub.length() - 1; j >= 0; j--)// {// string prev = sub.substr(0, j);// string suf = sub.substr(sub.length() - j, j);// if (prev == suf)// {// nxt[i] = j;// break;// }// }// }// return nxt;// }vector<int> getNxt(string &pattern){vector<int> nxt;// next[0] 必然是 0nxt.push_back(0);// 从 next[1] 开始求int x = 1, now = 0;while (x < pattern.length()){if (pattern[now] == pattern[x]){// 如果 pattern[now] == pattern[x],向右拓展一位now++;x++;nxt.push_back(now);}else if (now != 0){// 缩小 now,改成 nxt[now - 1]now = nxt[now - 1];}else{// now 已经为 0,无法再缩小,故 next[x] = 0nxt.push_back(0);x++;}}return nxt;}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 为字符串 text 的长度。
空间复杂度:O(n)。