枚举。
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))。
贪心。
一个数能被 25 整除,有如下五种情况:
设字符串的长度为 n。
我们从字符串的末尾往开头遍历,设当前数位为 digit,使用数组 count 记录数位的出现次数。
假设我们遍历到第 i 位,有 digit = num[i] - ‘0’,此时:
其他情况,我们都必须将字符串删到只剩 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 的长度。
前缀和。
对于本题,由于需要统计 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 的长度。
超出能力范围。
题解:LCA 模板(Python/Java/C++/Go)