Leetcode 第 111 场双周赛题解
- Leetcode 第 111 场双周赛题解
- 题目1:2824. 统计和小于目标的下标对数目
- 思路
- 代码
- 复杂度分析
- 题目2:2825. 循环增长使字符串子序列等于另一个字符串
- 思路
- 代码
- 复杂度分析
- 题目3:2826. 将三个组排序
- 思路
- 代码
- 复杂度分析
- 题目4:2827. 范围中美丽整数的数目
- 思路
- 代码
- 复杂度分析
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]);elseg[j] = nums[i];}return n - g.size();}
};
// @lc code=end
复杂度分析
时间复杂度:O(nlogn),其中 n 是数组 nums 的元素个数。
空间复杂度:O(n),其中 n 是数组 nums 的元素个数。
题目4:2827. 范围中美丽整数的数目
思路
题解:数位 DP(Python/Java/C++/Go)
代码
/** @lc app=leetcode.cn id=2827 lang=cpp** [2827] 范围中美丽整数的数目*/// @lc code=start// 数位 DPclass 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;// 枚举要填入的数字 dfor (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