Leetcode 第 361 场周赛题解
- Leetcode 第 361 场周赛题解
- 题目1:2843. 统计对称整数的数目
- 思路
- 代码
- 复杂度分析
- 题目2:生成特殊数字的最少操作
- 思路
- 代码
- 复杂度分析
- 题目3:统计趣味子数组的数目
- 思路
- 代码
- 复杂度分析
- 题目4:边权重均等查询
Leetcode 第 361 场周赛题解
题目1:2843. 统计对称整数的数目
思路
枚举。
代码
class Solution
{
public:
int countSymmetricIntegers(int low, int high)
{
int count = 0;
for (int num = low; num <= high; num++)
if (check(num))
count++;
return count;
}
// 辅函数 - 判断 x 是不是一个对称整数
bool check(int x)
{
vector<int> digits;
while (x)
{
digits.push_back(x % 10);
x /= 10;
}
if (digits.size() % 2 == 1)
return false;
int sum = 0;
for (int i = 0; i < digits.size() / 2; i++)
sum += digits[i];
for (int i = digits.size() / 2; i < digits.size(); i++)
sum -= digits[i];
return sum == 0;
}
};
取巧做法:将数字转化为字符串。
class Solution
{
public:
int countSymmetricIntegers(int low, int high)
{
int count = 0;
for (int num = low; num <= high; num++)
{
string s = to_string(num);
if (s.size() % 2 == 0 && accumulate(s.begin(), s.begin() + s.size() / 2, 0) == accumulate(s.begin() + s.size() / 2, s.end(), 0))
count++;
}
return count;
}
};
复杂度分析
时间复杂度:O((high−low)*log(high))。
空间复杂度:O(log(high))。
题目2:生成特殊数字的最少操作
思路
贪心。
一个数能被 25 整除,有如下五种情况:
- 这个数是 0。
- 这个数以 00 结尾。
- 这个数以 25 结尾。
- 这个数以 50 结尾。
- 这个数以 75 结尾。
设字符串的长度为 n。
我们从字符串的末尾往开头遍历,设当前数位为 digit,使用数组 count 记录数位的出现次数。
假设我们遍历到第 i 位,有 digit = num[i] - ‘0’,此时:
- 当 count[0] = 2 时,不管 digit 是什么,我们都可以构建一个以 00 结尾的数字。第 0 位到第 i 位的数字可以保留,后面两个 0 可以保留,其他位删除,所以一共需要删除 n - (i + 3) 位数字。
- 当 digit = 2 && count[5] > 0 时,我们都可以构建一个以 25 结尾的数字。第 0 位到第 i 位的数字可以保留,后面的 5 也可以保留,其他位删除,所以一共需要删除 n - (i + 2) 位数字。
- 同理,当 digit = 5 && count[0] > 0 时,我们都可以构建一个以 50 结尾的数字,一共需要删除 n - (i + 2) 位数字;当 digit = 7 && count[5] > 0 时,我们都可以构建一个以 75 结尾的数字,一共需要删除 n - (i + 2) 位数字。
- 最后别忘了 count[digit]++。
其他情况,我们都必须将字符串删到只剩 0 为止,删除次数为 n - count[0]。
代码
/*
* @lc app=leetcode.cn id=2844 lang=cpp
*
* [2844] 生成特殊数字的最少操作
*/
// @lc code=start
class Solution
{
public:
int minimumOperations(string num)
{
int n = num.size();
vector<int> count(10, 0);
for (int i = n - 1; i >= 0; i--)
{
int digit = num[i] - '0';
// 以00结尾
if (count[0] == 2)
return n - i - 3;
// 以25/50/75结尾
if ((digit == 2 && count[5]) || (digit == 5 && count[0]) || (digit == 7 && count[5]))
return n - i - 2;
count[digit]++;
}
// 删到只剩0
return n - count[0];
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 为字符串 num 的长度。
空间复杂度:O(n),其中 n 为字符串 num 的长度。
题目3:统计趣味子数组的数目
思路
前缀和。
对于本题,由于需要统计 cnt,我们可以把满足 nums[i] % modulo = k 的 nums[i] 视作 1,不满足则视作 0。
用数组 fun 记录上述结果。
如此转换后,算出 fun 的前缀和数组 preSum,那么题目中的 cnt 等价于 preSum[right + 1] - preSum[left]。
枚举 left 和 right,计算趣味子数组的数目,即满足 (preSum[right + 1] - preSum[left]) % modulo = k 的个数。
/*
* @lc app=leetcode.cn id=2845 lang=cpp
*
* [2845] 统计趣味子数组的数目
*/
// @lc code=start
class Solution
{
public:
long long countInterestingSubarrays(vector<int> &nums, int modulo, int k)
{
int n = nums.size();
vector<int> fun(n, 0);
for (int i = 0; i < n; i++)
if (nums[i] % modulo == k)
fun[i] = 1;
vector<int> preSum(n + 1, 0);
for (int i = 1; i <= n; i++)
preSum[i] = preSum[i - 1] + fun[i - 1];
long long ans = 0;
for (int left = 0; left < n; left++)
for (int right = left; right < n; right++)
{
int cnt = preSum[right + 1] - preSum[left];
if (cnt % modulo == k)
ans++;
}
return ans;
}
};
// @lc code=end
结果超时了:
优化:
(preSum[right + 1] - preSum[left]) % modulo = k 等价于 preSum[left] % modulo = (preSum[right + 1] − k) % modulo。
根据上式,我们可以一边枚举 right,一边用一个哈希表统计有多少个 preSum[right + 1] % modulo,这样可以快速知道有多少个 (preSum[right + 1] − k) % modulo,也就是 preSum[left] % modulo 的个数,把个数加到答案中。
代码
/*
* @lc app=leetcode.cn id=2845 lang=cpp
*
* [2845] 统计趣味子数组的数目
*/
// @lc code=start
class Solution
{
public:
long long countInterestingSubarrays(vector<int> &nums, int modulo, int k)
{
int n = nums.size();
vector<int> fun(n, 0);
for (int i = 0; i < n; i++)
if (nums[i] % modulo == k)
fun[i] = 1;
vector<int> preSum(n + 1, 0);
for (int i = 1; i <= n; i++)
preSum[i] = preSum[i - 1] + fun[i - 1];
long long ans = 0;
unordered_map<int, int> cnt;
cnt[0] = 1; // 把 preSum[0] = 0 算进去
for (int right = 0; right < n; right++)
{
ans += cnt[(preSum[right + 1] - k + modulo) % modulo];
cnt[preSum[right + 1] % modulo]++;
}
return ans;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 是数组 nums 的长度。
空间复杂度:O(n),其中 n 是数组 nums 的长度。
题目4:边权重均等查询
超出能力范围。
题解:LCA 模板(Python/Java/C++/Go)