Leetcode 第 111 场双周赛题解
Leetcode 第 111 场双周赛题解
题目1:2824. 统计和小于目标的下标对数目
思路
两层循环搞定。
代码
/*
* @lc app=leetcode.cn id=2824 lang=cpp
*
* [2824] 统计和小于目标的下标对数目
*/
// @lc code=start
class Solution
{
public:
int countPairs(vector<int> &nums, int target)
{
int n = nums.size();
int count = 0;
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
if (nums[i] + nums[j] < target)
count++;
return count;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n2),其中 n 是数组 nums 的长度。
空间复杂度:O(1)。
题目2:2825. 循环增长使字符串子序列等于另一个字符串
思路
设置两个指针 i 和 j,分别指向字符串 str1 和 str2 的第一个字符。
双指针遍历 str1[i] 和 str2[j],如果 str1[i] 可以匹配 str2[j],那么 i 和 j 都加一,否则只有 i 加一。
匹配的含义是 str1[i] 等于 str2[j],或者 str1[i] 循环递增的下一个字符等于 str2[j]。
如果 j 等于 str2 的长度,则返回 true,否则返回 false。
代码
/*
* @lc app=leetcode.cn id=2825 lang=cpp
*
* [2825] 循环增长使字符串子序列等于另一个字符串
*/
// @lc code=start
class Solution
{
public:
bool canMakeSubsequence(string str1, string str2)
{
// 特判
if (str1.length() < str2.length())
return false;
if (str1 == str2)
return true;
int len1 = str1.length(), len2 = str2.length();
int i = 0, j = 0;
for (int i = 0; i < len1; i++)
{
if (match(str1[i], str2[j]))
j++;
if (j == len2)
return true;
}
return false;
}
// 辅函数 - 判断字符 c1 和 c2 是否匹配
bool match(char c1, char c2)
{
if (c1 == c2)
return true;
c1 = c1 == 'z' ? 'a' : char(c1 + 1);
return c1 == c2;
// return (c2 - c1 + 26) % 26 <= 1;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(len1 + len2,其中 len1 是字符串 str1 的长度,len2 是字符串 str2 的长度。
空间复杂度:O(1)。
题目3:2826. 将三个组排序
思路
最长递增子序列的变种题。
利用 Leetcode300. 最长递增子序列 的方法,求出数组 nums 的最长递增子序列 g,最后答案为 nums.size() - g.size()。

代码
/*
* @lc app=leetcode.cn id=2826 lang=cpp
*
* [2826] 将三个组排序
*/
// @lc code=start
class Solution
{
public:
int minimumOperations(vector<int> &nums)
{
// 特判
if (nums.empty())
return 0;
int n = nums.size();
vector<int> g; // 最长递增子序列
for (int i = 0; i < n; i++)
{
int j = upper_bound(g.begin(), g.end(), nums[i]) - g.begin();
if (j == g.size())
g.push_back(nums[i]);
else
g[j] = nums[i];
}
return n - g.size();
}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
题目4:2827. 范围中美丽整数的数目
思路
代码
/*
* @lc app=leetcode.cn id=2827 lang=cpp
*
* [2827] 范围中美丽整数的数目
*/
// @lc code=start
// 数位 DP
class Solution
{
public:
int numberOfBeautifulIntegers(int low, int high, int k)
{
return countBIfrom1toN(high, k) - countBIfrom1toN(low - 1, k);
}
// 辅函数 - 计算 [1, n] 的美丽整数的数目
int countBIfrom1toN(int n, int k)
{
string s = to_string(n);
int len = s.length(), memo[len][k + 1][len * 2 + 1];
memset(memo, -1, sizeof(memo)); // -1 表示没有计算过
function<int(int, int, int, bool, bool)> dfs;
// 返回从 i 开始填数字,前面填的数字集合是 mask,能构造出的特殊整数的数目
// diff: 奇数数位的数目 - 偶数数位的数目
// is_limit 表示前面填的数字是否都是 n 对应位上的,
// 如果为 true,那么当前位至多为 s[i],否则至多为 9
// is_num 表示前面是否填了数字(是否跳过),
// 如果为 true,那么当前位可以从 0 开始,否则当前位可以跳过,或者从 1 开始填数字
dfs = [&](int i, int val, int diff, bool is_limit, bool is_num) -> int
{
if (i == len)
{
// 找到了一个合法数字
return is_num && val == 0 && diff == len;
}
if (!is_limit && is_num && memo[i][val][diff] != -1)
return memo[i][val][diff];
int res = 0;
if (!is_num)
{
// 可以跳过当前数位
res = dfs(i + 1, val, diff, false, false);
}
// 如果前面填的数字都和 n 的一样,那么这一位至多填数字 s[i](否则就超过 n 啦)
int up = is_limit ? s[i] - '0' : 9;
// 枚举要填入的数字 d
for (int d = 1 - is_num; d <= up; d++)
res += dfs(i + 1, (val * 10 + d) % k, diff + d % 2 * 2 - 1, is_limit && d == up, true);
if (!is_limit && is_num)
memo[i][val][diff] = res; // 记忆化
return res;
};
return dfs(0, 0, len, true, false);
}
};
// @lc code=end
复杂度分析

1125

被折叠的 条评论
为什么被折叠?



