leetcode weekly contest 389
周赛质量还不错, t4
是个不错的题目,前 3
题太差了。
3083. 字符串及其反转中是否存在同一子字符串
给你一个字符串 s
,请你判断字符串 s
是否存在一个长度为 2
的子字符串,在其反转后的字符串中也出现。
如果存在这样的子字符串,返回 true
;如果不存在,返回 false
。
示例 1:
输入:s = “leetcode”
输出:true
解释:子字符串 "ee"
的长度为 2
,它也出现在 reverse(s) == "edocteel"
中。
示例 2:
输入:s = “abcba”
输出:true
解释:所有长度为 2
的子字符串 "ab"
、"bc"
、"cb"
、"ba"
也都出现在 reverse(s) == "abcba"
中。
示例 3:
输入:s = “abcd”
输出:false
解释:字符串 s
中不存在满足「在其反转后的字符串中也出现」且长度为 2
的子字符串。
提示:
1 <= s.length <= 100
- 字符串
s
仅由小写英文字母组成。
地址
题意
模拟
思路
- 按照题目要求进行模拟即可,并返回结果即可
- 复杂度分析:
- 时间复杂度:$O(n^3)$,其中 $n$ 表示给定字符串的长度。
- 空间复杂度:$O(1)$。
代码
class Solution: |
impl Solution { |
3084. 统计以给定字符开头和结尾的子字符串总数
给你一个字符串 s
和一个字符 c
。返回在字符串 s
中并且以 c
字符开头和结尾的非空子字符串的总数。
示例 1:
输入:s = “abada”, c = “a”
输出:6
解释:以 "a"
开头和结尾的子字符串有: "**a**bada"
、"**aba**da"
、"**abada**"
、"ab**a**da"
、"ab**ada**"
、"abad**a**"
。
示例 2:
输入:s = “zzz”, c = “z”
输出:6
解释:字符串 s
中总共有 6
个子字符串,并且它们都以 "z"
开头和结尾。
提示:
1 <= s.length <= 105
s
和c
均由小写英文字母组成。
地址
题意
数学问题
思路
- 排列组合问题,假设有 $n$个相同的字符,此时我们从 $n$ 个字符中任意选择两个字符作为开头和结尾,还需要考虑单个字符的情况,此时一共有 $\dfrac{n \times (n + 1)}{2}$ 个。
- 复杂度分析:
- 时间复杂度:$O(n)$,其中 $n$ 表示给定字符串的长度。
- 空间复杂度:$O(n)$, 其中 $n$ 表示给定字符串的长度。
代码
class Solution: |
impl Solution { |
3085. 成为 K 特殊字符串需要删除的最少字符数
给你一个字符串 word
和一个整数 k
。
如果 |freq(word[i]) - freq(word[j])| <= k
对于字符串中所有下标 i
和 j
都成立,则认为 word
是 k 特殊字符串。
此处,freq(x)
表示字符 x
在 word
中的出现频率,而 |y|
表示 y
的绝对值。
返回使 word
成为 k 特殊字符串 需要删除的字符的最小数量。
示例 1:
输入:word = “aabcaba”, k = 0
输出:3
解释:可以删除 2
个 "a"
和 1
个 "c"
使 word
成为 0
特殊字符串。word
变为 "baba"
,此时 freq('a') == freq('b') == 2
。
示例 2:
输入:word = “dabdcbdcdcd”, k = 2
输出:2
解释:可以删除 1
个 "a"
和 1
个 "d"
使 word
成为 2
特殊字符串。word
变为 "bdcbdcdcd"
,此时 freq('b') == 2
,freq('c') == 3
,freq('d') == 4
。
示例 3:
输入:word = “aaabaaa”, k = 2
输出:1
解释:可以删除 1 个 "b"
使 word
成为 2
特殊字符串。因此,word
变为 "aaaaaa"
,此时每个字母的频率都是 6
。
提示:
1 <= word.length <= 105
0 <= k <= 105
word
仅由小写英文字母组成。
地址
https://leetcode.cn/contest/weekly-contest-389/problems/minimum-deletions-to-make-string-k-special/
题意
模拟 + 枚举
思路
题目所谓的频率,题目可以转换为给定数组,使得数组中任意元素的差的绝对值均小于等于 $k$,根据贪心原则可以知道所有的数的区间一定处在 $[nums[i], nums[i] +x]$ 或者 $[nums[i] - x, nums[i]]$ 这两个区间内,此时我们直接枚举,枚举区间的左侧和右侧 $nums[i]$,分别求出最小的删除数量即可。
复杂度分析:
- 时间复杂度:$O(n \times \Sigma)$, $n$ 表示给定字符串数组的长度, $\Sigma$ 表示字符的种类;
- 空间复杂度:$O(n)$,, $n$ 表示定字符串数组的长度
代码
class Solution: |
use std::collections::HashMap; |
3086. 拾起 K 个 1 需要的最少行动次数
给你一个下标从 0 开始的二进制数组 nums
,其长度为 n
;另给你一个 正整数 k
以及一个 非负整数 maxChanges
。
Alice 在玩一个游戏,游戏的目标是让 Alice 使用 最少 数量的 行动 次数从 nums
中拾起 k
个 1 。游戏开始时,Alice 可以选择数组 [0, n - 1]
范围内的任何索引index
站立。如果 nums[index] == 1
,Alice 会拾起一个 1 ,并且 nums[index]
变成0
(这 不算 作一次行动)。之后,Alice 可以执行 任意数量 的 行动(包括****零次),在每次行动中 Alice 必须 恰好 执行以下动作之一:
- 选择任意一个下标
j != index
且满足nums[j] == 0
,然后将nums[j]
设置为1
。这个动作最多可以执行maxChanges
次。 - 选择任意两个相邻的下标
x
和y
(|x - y| == 1
)且满足nums[x] == 1
,nums[y] == 0
,然后交换它们的值(将nums[y] = 1
和nums[x] = 0
)。如果y == index
,在这次行动后 Alice 拾起一个 1 ,并且nums[y]
变成0
。
返回 Alice 拾起 恰好 k
个 1 所需的 最少 行动次数。
示例 1:
输入:nums = [1,1,0,0,0,1,1,0,0,1], k = 3, maxChanges = 1
输出:3
解释:如果游戏开始时 Alice 在 index == 1
的位置上,按照以下步骤执行每个动作,他可以利用 3
次行动拾取 3
个 1 :
- 游戏开始时 Alice 拾取了一个 1 ,
nums[1]
变成了0
。此时nums
变为[1,**0**,0,0,0,1,1,0,0,1]
。 - 选择
j == 2
并执行第一种类型的动作。nums
变为[1,**0**,1,0,0,1,1,0,0,1]
- 选择
x == 2
和y == 1
,并执行第二种类型的动作。nums
变为[1,**1**,0,0,0,1,1,0,0,1]
。由于y == index
,Alice 拾取了一个 1 ,nums
变为[1,**0**,0,0,0,1,1,0,0,1]
。 - 选择
x == 0
和y == 1
,并执行第二种类型的动作。nums
变为[0,**1**,0,0,0,1,1,0,0,1]
。由于y == index
,Alice 拾取了一个 1 ,nums
变为[0,**0**,0,0,0,1,1,0,0,1]
。
请注意,Alice 也可能执行其他的 3
次行动序列达成拾取 3
个 1 。
示例 2:
输入:nums = [0,0,0,0], k = 2, maxChanges = 3
输出:4
解释:如果游戏开始时 Alice 在 index == 0
的位置上,按照以下步骤执行每个动作,他可以利用 4
次行动拾取 2
个 1 :
- 选择
j == 1
并执行第一种类型的动作。nums
变为[**0**,1,0,0]
。 - 选择
x == 1
和y == 0
,并执行第二种类型的动作。nums
变为[**1**,0,0,0]
。由于y == index
,Alice 拾起了一个 1 ,nums
变为[**0**,0,0,0]
。 - 再次选择
j == 1
并执行第一种类型的动作。nums
变为[**0**,1,0,0]
。 - 再次选择
x == 1
和y == 0
,并执行第二种类型的动作。nums
变为[**1**,0,0,0]
。由于y == index
,Alice 拾起了一个 1 ,nums
变为[**0**,0,0,0]
。
提示:
2 <= n <= 105
0 <= nums[i] <= 1
1 <= k <= 105
0 <= maxChanges <= 105
maxChanges + sum(nums) >= k
地址
https://leetcode.cn/contest/weekly-contest-389/problems/minimum-moves-to-pick-k-ones/
题意
贪心 + 二分查找
思路
- 题目本身倒不是特别难,但是细节处理起来非常容易出错,所以比赛的时候如果要把题目全部作对其实挺不容易,我们可以分析一下以下贪心原则:
- 首先假如选的 $index$ 有 $1$ ,此时直接拾起这个 $1$ ,需要的花费为 $0$;
- 其次我们优先选择 $index$ 两侧的 $1$,拾起两侧的 $1$ 需要的花费为 $1$,最多只有 $2$ 个这样的 $1$ 可以选择;
- 再次我们可以优先选择使用第一种行动,在 $index$ 的两侧选择一个位置填入 $1$ ,然后再选择使用第二种变换拾起 $1$, 每拾起 $1$ 个 $1$ 需要的行动次数为 $2$ ;
- 最后我们再选择其它的 $1$ 将起拾起,次数第 $i$ 个索引上的 $1$ 需要耗费的变换次数为 $|i - index|$,假设此时我们还需要拾起 $x$ ,我们直接利用二分查找找到距离 $i$ 的最小距离 $j$,使得区间 $[i-j,i-2]\cup[i+2, i + j]$ 中 $1$ 的数目大于等于 $x$ ,此时还需要处理奇偶数的关系,我们减掉一个距离 $index$,最远的 $1$ 即可。
- 题目不是很难,但是细节处理特别麻烦,二分查找的关键是我们要处理好各种细节问题,利用前缀和求出区间中 $1$ 的数目,以及求出需要变换的最少次数。
- 复杂度分析:
- 时间复杂度:$O(n\log n)$,其中 $n$ 表示给定数组的长度。
- 空间复杂度:$O(n)$,其中 $n$ 表示给定数组的长度。
代码
class Solution: |
use std::cmp::min; |
欢迎关注和打赏,感谢支持!
扫描二维码,分享此文章