记录 LeetCode 第 298 场周赛
本次周赛依旧只写出前三题,第四题到饭点了。(在家里,不吃饭要被线下gank)。
战局详情
排名 | 用户名 | 得分 | 完成时间 | 题目1(3) | 题目2(4) | 题目3(5) | 题目4(6) |
---|---|---|---|---|---|---|---|
844 / 6228 | Juruoer | 12 | 1:07:07 | 0:10:16 | 0:27:01 1 | 1:02:07 |
题目及解答
兼具大小写的最好英文字母
给你一个由英文字母组成的字符串 s
,请你找出并返回 s
中的 最好 英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。
最好 英文字母的大写和小写形式必须 都 在 s
中出现。
英文字母 b
比另一个英文字母 a
更好 的前提是:英文字母表中,b
在 a
之 后 出现。
提示:
1 <= s.length <= 1000
s
由小写和大写英文字母组成
示例一:
输入:s = “lEeTcOdE”
输出:“E”
解释:
字母 ‘E’ 是唯一一个大写和小写形式都出现的字母。
示例二:
输入:s = “arRAzFif”
输出:“R”
解释:
字母 ‘R’ 是大写和小写形式都出现的最好英文字母。
注意 ‘A’ 和 ‘F’ 的大写和小写形式也都出现了,但是 ‘R’ 比 ‘F’ 和 ‘A’ 更好。
示例三:
输入:s = “AbCdEfGhIjK”
输出:“”
解释:
不存在大写和小写形式都出现的字母。
解决方案:
模拟:
按题意模拟即可。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。其中 n
为 s
的长度,c
为字符的种类数,本题字符仅有 种。
个位数字为 K 的整数之和
给你两个整数 num
和 k
,考虑具有以下属性的正整数多重集:
- 每个整数个位数字都是
k
。 - 所有整数之和是
num
。
返回该多重集的最小大小,如果不存在这样的多重集,返回 -1
。
注意:
- 多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。
- 个位数字 是数字最右边的数位。
提示:
0 <= num <= 3000
0 <= k <= 9
示例一:
输入:num = 58, k = 9
输出:2
解释:
多重集 [9,49] 满足题目条件,和为 58 且每个整数的个位数字是 9 。
另一个满足条件的多重集是 [19,39] 。
可以证明 2 是满足题目条件的多重集的最小长度。
示例二:
输入:num = 37, k = 2
输出:-1
解释:个位数字为 2 的整数无法相加得到 37 。
示例三:
输入:num = 0, k = 7
输出:0
解释:空多重集的和为 0 。
解决方案:
枚举:
由题意可知,若存在这样的多重集,则 num = (a1 * 10 + k) + (a2 * 10 + k) + ... + (an * 10 + k) = p * 10 + nk
,n
即 该多重集的大小。
那么只需要枚举n
,找到第一个满足 (num - n * k) % 10 == 0
的 n
,即最小的多重集大小。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。
小于等于 K 的最长二进制子序列
给你一个二进制字符串 s
和一个正整数 k
。
请你返回 s
的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k
。
注意:
- 子序列可以有 前导
0
。 - 空字符串视为
0
。 - 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。
提示:
1 <= s.length <= 1000
s[i]
要么是'0'
,要么是'1'
。1 <= k <= 1e9
示例一:
输入:s = “1001010”, k = 5
输出:5
解释:s 中小于等于 5 的最长子序列是 “00010” ,对应的十进制数字是 2 。
注意 “00100” 和 “00101” 也是可行的最长子序列,十进制分别对应 4 和 5 。
最长子序列的长度为 5 ,所以返回 5 。
示例二:
输入:s = “00101001”, k = 1
输出:6
解释:“000001” 是 s 中小于等于 1 的最长子序列,对应的十进制数字是 1 。
最长子序列的长度为 6 ,所以返回 6 。
解决方案:
一、贪心
从左到右遍历 s
,对于 s
的每一个字符,我们都将他放入二进制中,如果该二进制大于 k
,由于 k >= 1
,故 s
中一定存在 1
,我们将第一个 1
从二进制中去除掉。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度:。其中 m
为 k
的二进制长度(首位为 1
),n
为 s
的长度。
二、贪心 + 分类讨论
我们仔细观察方法一,发现方法一得出的子字符串一定包含 s
中的所有 0
,所以只需要从 s
中找到二进制小于等于 k
的最长后缀,该后缀的长度加上 s
中除去该后缀的部分的所有 0
的个数即所求。
另外我们发现这个最长后缀若长度大于 k
的二进制的长度,则多出的高位必然为前导 0
,所以我们只需要比较 s
的和 k
的二进制长度相同的后缀与 k
的关系即可。
设 s
的长度为 n
,k
的二进制(首位为 1
)的长度为 m
。
- 若
n <= m
,则s
的所有后缀的二进制均小于等于k
,返回 n。 - 若
n > m
,且s
的长为m
的后缀的二进制小于等于k
,返回s
中除去长为m
的后的部分的0
的个数 +m
。 - 若
n > m
,且s
的成为m
的后缀的二进制大于k
,说明s
的长为m
的后缀以'1'
开头,又s
的长为m - 1
的后缀的二进制必小于k
,故返回s
中除去长为m
的后的部分的0
的个数 +m - 1
。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。其中 m
为 k
的二进制长度(首位为 1
),n
为 s
的长度。
卖木头块
给你两个整数 m
和 n
,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices
,其中 prices[i] = [hi, wi, pricei]
表示你可以以 pricei
元的价格卖一块高为 hi
宽为 wi
的矩形木块。
每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:
- 沿垂直方向按高度 完全 切割木块,或
- 沿水平方向按宽度 完全 切割木块
在将一块木块切成若干小木块后,你可以根据 prices
卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。
请你返回切割一块大小为 m x n
的木块后,能得到的 最多 钱数。
注意你可以切割木块任意次。
提示:
1 <= m, n <= 200
1 <= prices.length <= 2 * 1e4
prices[i].length == 3
1 <= hi <= m
1 <= wi <= n
1 <= pricei <= 1e6
- 所有
(hi, wi)
互不相同 。
示例一:
输入:m = 3, n = 5, prices = [[1,4,2],[2,2,7],[2,1,3]]
输出:19
解释:上图展示了一个可行的方案。包括:
- 2 块 2 x 2 的小木块,售出 2 * 7 = 14 元。
- 1 块 2 x 1 的小木块,售出 1 * 3 = 3 元。
- 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。
总共售出 14 + 3 + 2 = 19 元。
19 元是最多能得到的钱数。
示例二:
输入:m = 4, n = 6, prices = [[3,2,10],[1,4,2],[4,1,3]]
输出:32
解释:上图展示了一个可行的方案。包括:
- 3 块 3 x 2 的小木块,售出 3 * 10 = 30 元。
- 1 块 1 x 4 的小木块,售出 1 * 2 = 2 元。
总共售出 30 + 2 = 32 元。
32 元是最多能得到的钱数。
注意我们不能旋转 1 x 4 的木块来得到 4 x 1 的木块。
解决方案:
动态规划:
对于高度为 i
宽度为 j
的木块,假设其最多能卖出的价格为 dp[i][j]
,我们可以将其分割为
- 高度为
i
,宽度分别为k
和j - k
的两块,其中k
大于0
且 小于j
,或是 - 宽度为
j
, 高度分别为k
和i - k
的两块,其中k
大于0
且 小于i
。
故 dp[i][j] = max(max(dp[i][k] + dp[i][j - k]), max(dp[k][j] + dp[i - k][j]))
。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度:。其中 c
为 prices
的长度。