力扣周赛第01弹----思维 与 dp
一、成为 K 特殊字符串需要删除的最少字符数
题目
给你一个字符串 word
和一个整数 k
。
如果 |freq(word[i]) - freq(word[j])| <= k
对于字符串中所有下标 i
和 j
都成立,则认为 word
是 k 特殊字符串。
此处,freq(x)
表示字符 x
在 word
中的出现频率,而 |y|
表示 y
的绝对值。
返回使 word
成为 k 特殊字符串 需要删除的字符的最小数量。
示例
输入:word = "aabcaba", k = 0
输出:3
解释:可以删除 2
个 "a"
和 1
个 "c"
使 word
成为 0
特殊字符串。word
变为 "baba"
,此时 freq('a') == freq('b') == 2
。
提示:
- \(1 <= word.length <= 10^5\)
- \(0 <= k <= 10^5\)
word
仅由小写英文字母组成。
思路
- ①因为题目中只有26个小写英文字母,所以最多只会出现26个频数
- ②考虑将频数按照从小到达排序,枚举最后保存频数的最小值x
- ③将剩余的大于x + k的频数,变成x + k,小于x + k的就直接保留,计算保留的最大值,然后用总频数 - 保留值,即为删除最小数量
代码
class Solution:
def minimumDeletions(self, word: str, k: int) -> int:
cnt = sorted(Counter(word).values())
max_save = 0
for i,x in enumerate(cnt):
s = 0
for y in cnt[i:]:
s += min(y,x + k)
max_save = max(max_save,s)
return len(word) - max_save
二、求出所有子序列的能量和
题目
给你一个长度为 n
的整数数组 nums
和一个 正 整数 k
。一个整数数组的 能量 定义为和 等于 k
的子序列的数目。
请你返回 nums
中所有子序列的 能量和 。
由于答案可能很大,请你将它对 \(10^9 + 7\) 取余 后返回。
示例
输入: nums = [1,2,3], k = 3
输出: 6
解释:
总共有 5
个能量不为 0 的子序列:
- 子序列 [1,2,3]
有
2个和为
3的子序列:
[3] 和 [1,2] 。 - 子序列 [1,3]
有
1个和为
3的子序列:
[3] 。 - 子序列 [2,3]
有
1个和为
3的子序列:
[3] 。 - 子序列[1,2]
有
1个和为
3的子序列:
[1,2]。 - 子序列[3]
有
1个和为
3的子序列:
[3] 。
所以答案为 2 + 1 + 1 + 1 + 1 = 6
。
提示:
- \(1 <= n <= 100\)
- \(1 <= nums[i] <= 10^4\)
- \(1 <= k <= 100\)
思路一
-
①设
dp[i][j]
为从前i
个数中选出子序列,子序列得到和为j
的方案数的总和; -
②易知,
dp[i][j]
=dp[i - 1][j] * 2
-
③同时,
dp[i][j] = dp[i][j] + dp[i - 1][j - num[i]]
-
④注意,
dp[0][0] = 1
的初始化 -
⑤综上,可列出状态转移方程写出程序!
代码
MOD = int(1e9 + 7)
class Solution:
def sumOfPower(self, nums: List[int], k: int) -> int:
n = len(nums)
dp = [[0 for _ in range(k + 1)]for _ in range(n + 1)]
dp[0][0] = 1
for i in range(n):
for j in range(k + 1):
dp[i + 1][j] = dp[i][j] * 2 % MOD
if j >= nums[i]:
dp[i + 1][j] = (dp[i + 1][j] + dp[i][j - nums[i]]) % MOD
return dp[n][k]
由于只用到了 i + 1
与i
两个状态,所以第一位可以优化掉,不过第二维要从从后往前枚举!
MOD = int(1e9 + 7)
class Solution:
def sumOfPower(self, nums: List[int], k: int) -> int:
n = len(nums)
dp = [0 for _ in range(k + 1)]
dp[0] = 1
for i in range(n):
for j in range(k,-1,-1): # 从后往前枚举
dp[j] = dp[j] * 2 % MOD
if j >= nums[i]:
dp[j] = (dp[j] + dp[j - nums[i]]) % MOD
return dp[k]
思路二
-
①对于
nums = [1,2,3,4,5]
,k=3
,考虑到如果我们知道1 + 2 = 3
,那么包含1、2
对和为k的子序列的贡献为 \(2^{5-2}\) -
②所以我们只要求出,和为
k
的,长度为m
的子序列的个数cnt
,就能求出贡献为 $ 2^{n - m} × cnt$ -
③设
dp[i][j][k]
为从前i
个数中选出和为j
,且长度为k
的子序列的个数! -
④
dp[i][j][k]
=dp[i - 1][j][k]
->不选第i
个物品 -
⑤
dp[i][j][k]
=dp[i][j - nums[i]][k - 1]
->选第i
个物品
代码
MOD = int(1e9 + 7)
class Solution:
def sumOfPower(self, nums: List[int], k: int) -> int:
n = len(nums)
dp = [[[0] * (n + 1) for _ in range(k + 1)]for _ in range(n + 1)]
for i in range(n + 1):
dp[i][0][0] = 1
for i in range(n):
for j in range(1,k + 1):
for c in range(1,n + 1):
if j >= nums[i]:
dp[i + 1][j][c] = dp[i][j][c] + dp[i][j - nums[i]][c - 1]
dp[i + 1][j][c] %= MOD
else:
dp[i + 1][j][c] = dp[i][j][c]
ans = 0
for i in range(1,n + 1):
ans = (ans + pow(2,n - i,MOD) * dp[n][k][i]) % MOD
return ans
这也是可以优化第一维的,这里就不再赘述!
标签:周赛,01,word,nums,int,力扣,range,序列,dp From: https://www.cnblogs.com/gebeng/p/18078670