Leetcode 第 411 场周赛题解
Leetcode 第 411 场周赛题解
题目1:3258. 统计满足 K 约束的子字符串数量 I
思路
暴力枚举每一个子字符串,看是否满足 k 约束。
代码
/*
* @lc app=leetcode.cn id=3258 lang=cpp
*
* [3258] 统计满足 K 约束的子字符串数量 I
*/
// @lc code=start
class Solution
{
public:
int countKConstraintSubstrings(string s, int k)
{
int n = s.length();
function<bool(string)> check = [&](string s) -> bool
{
int cnt0 = 0, cnt1 = 0;
for (char &c : s)
{
if (c == '0')
cnt0++;
else
cnt1++;
if (cnt0 > k && cnt1 > k)
return false;
}
return true;
};
int cnt = 0;
for (int i = 0; i < n; i++)
for (int j = i; j < n; j++)
{
string temp = s.substr(i, j - i + 1);
if (check(temp))
cnt++;
}
return cnt;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n2),其中 n 是字符串 s 的长度。
空间复杂度:O(1)。
题目2:3259. 超级饮料的最大强化能量
思路
本题的状态定义 dfs(i,j)。其中 j=0,1,分别表示最后选的是 energyDrinkA[i] 还是 energyDrinkB[i]。
为方便实现,把 energyDrinkA 和 energyDrinkB 加到一个长为 2 的二维数组 c 中。
分类讨论:
-
继续选 c[j] 中的元素,那么下一个数选 c[j][i−1],需要解决的问题为:从下标 [0,i−1] 中选数字,且最后选的是 c[j] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−1,j)。
-
改成选 c[j⊕1] 中的元素,那么下一个数选 c[j⊕1][i−2],需要解决的问题为:从下标 [0,i−2] 中选数字,且最后选的是 c[j⊕1] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−2,j⊕1)。其中 ⊕ 为异或运算,通过异或 1,可以把 0 变成 1,把 1 变成 0。
代码
#
# @lc app=leetcode.cn id=3259 lang=python3
#
# [3259] 超级饮料的最大强化能量
#
# @lc code=start
class Solution:
def maxEnergyBoost(self, energyDrinkA: List[int], energyDrinkB: List[int]) -> int:
n = len(energyDrinkA)
energyDrink = (energyDrinkA, energyDrinkB)
@cache # 缓存装饰器,避免重复计算 dfs 的结果(记忆化)
def dfs(i: int, j: int) -> int:
if i < 0:
return 0
res1 = dfs(i - 1, j) + energyDrink[j][i]
res2 = dfs(i - 2, j ^ 1) + energyDrink[j][i]
return max(res1, res2)
return max(dfs(n - 1, 0), dfs(n - 1, 1))
# @lc code=end
复杂度分析
时间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。由于每个状态只会计算一次,动态规划的时间复杂度 = 状态个数 × 单个状态的计算时间。本题状态个数等于 O(n),单个状态的计算时间为 O(1),所以总的时间复杂度为 O(n)。
空间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。保存多少状态,就需要多少空间。
题目3:3260. 找出最大的 N 位 K 回文数
思路
找规律,打表。
- k = 1,3,9:所有位为9。
- k = 2,4,8:依次为首尾1,2,3位为8,其余位为9。
- k = 5:首尾位为5,其余位为9。
- k = 6:n>=3时,首尾位为8,奇数时中间一位为8,偶数时中间两位为7,其余位为9。
- k = 7:n=3开始,中间1或2位为577944644977循环,其余位为9。
代码
#
# @lc app=leetcode.cn id=3260 lang=python3
#
# [3260] 找出最大的 N 位 K 回文数
#
# @lc code=start
class Solution:
def largestPalindrome(self, n: int, k: int) -> str:
if k == 1:
return '9' * n
elif k == 2:
if n == 1:
return '8'
'''
1 8
2 88
3 898
4 8998
5 89998
6 899998
7 8999998
'''
return '8' + (n-2) * '9' + '8'
elif k == 3:
'''
1 9
2 99
3 999
4 9999
5 99999
6 999999
7 9999999
'''
return '9' * n
elif k == 4:
'''
1 8
2 88
3 888
4 8888
5 88988
6 889988
7 8899988
8 88999988
9 889999988
'''
if n <= 4:
return '8' * n
return '88' + (n-4) * '9' + '88'
# 5995
elif k == 5:
if n == 1:
return '5'
return '5' + (n-2) * '9' + '5'
elif k == 6:
'''
1 6
2 66
3 888
4 8778
5 89898
6 897798
7 8998998
'''
if n <= 2:
return '6' * n
# 8 9999 8 9999 8
if n % 2 == 1:
tmp = (n-3) // 2
return '8' + tmp * '9' + '8' + tmp * '9' + '8'
# 8 99 77 99 8
else:
tmp = (n-4) // 2
return '8' + tmp * '9' + '77' + tmp * '9' + '8'
elif k == 7:
'''
1 7
2 77
3 959
4 9779
5 99799
6 999999
7 9994999
8 99944999
9 999969999
'''
if n <= 2:
return '7' * n
if n % 2 == 1:
tmp = (n-1) // 2
for m in range(9,-1,-1):
s = '9' * tmp + str(m) + '9' * tmp
t = 0
for w in s:
t *= 10
t += int(w)
t %= k
if t == 0:
return s
else:
tmp = (n-2) // 2
for m in range(9,-1,-1):
s = '9' * tmp + str(m) + str(m) + '9' * tmp
t = 0
for w in s:
t *= 10
t += int(w)
t %= k
if t == 0:
return s
elif k == 8:
'''
1 8
2 88
3 888
4 8888
5 88888
6 888888
7 8889888
8 88899888
9 888999888
'''
if n <= 6:
return '8' * n
return '888' + (n-6) * '9' + '888'
elif k == 9:
# 同 3
return '9' * n
# @lc code=end
复杂度分析
时间复杂度:O(1)。
空间复杂度:O(1)。
题目4:3261. 统计满足 K 约束的子字符串数量 II
思路
滑动窗口+前缀和+二分查找/双指针。
题解:https://leetcode.cn/problems/count-substrings-that-satisfy-k-constraint-ii/solutions/2884463/hua-dong-chuang-kou-qian-zhui-he-er-fen-jzo25/
代码
/*
* @lc app=leetcode.cn id=3261 lang=cpp
*
* [3261] 统计满足 K 约束的子字符串数量 II
*/
// @lc code=start
class Solution
{
public:
vector<long long> countKConstraintSubstrings(string s, int k, vector<vector<int>> &queries)
{
int n = s.length();
vector<int> left(n);
vector<long long> sum(n + 1);
int cnt[2]{}, l = 0;
for (int i = 0; i < n; i++)
{
cnt[s[i] & 1]++;
while (cnt[0] > k && cnt[1] > k)
{
cnt[s[l++] & 1]--;
}
left[i] = l;
// 计算 i-left[i]+1 的前缀和
sum[i + 1] = sum[i] + i - l + 1;
}
vector<long long> ans(queries.size());
for (int i = 0; i < queries.size(); i++)
{
int l = queries[i][0], r = queries[i][1];
int j = lower_bound(left.begin() + l, left.begin() + r + 1, l) - left.begin();
ans[i] = sum[r + 1] - sum[j] + (long long)(j - l + 1) * (j - l) / 2;
}
return ans;
}
};
// @lc code=end
复杂度分析
时间复杂度:O(n+qlogn),其中 n 是数组 nums 的长度,q 是数组 queries 的长度。注意 l 只会增加不会减少,所以二重循环的时间复杂度为 O(n)。
空间复杂度:O(n),其中 n 是数组 nums 的长度。返回值不计入。