image.png
没想太明白,瞎搞肯定有问题

5242. 兼具大小写的最好英文字母

给你一个由英文字母组成的字符串 s ,请你找出并返回 s 中的 最好 英文字母。返回的字母必须为大写形式。如果不存在满足条件的字母,则返回一个空字符串。
最好 英文字母的大写和小写形式必须 在 s 中出现。
英文字母 b 比另一个英文字母 a 更好 的前提是:英文字母表中,b 在 a 之 出现。

示例 1:
输入:s = “lEe_TcOdE输出:“E” 解释: 字母 ‘E’ 是唯一一个大写和小写形式都出现的字母。
示例 2:
输入:s = “a
rR_AzFif” 输出:“R” 解释: 字母 ‘R’ 是大写和小写形式都出现的最好英文字母。 注意 ‘A’ 和 ‘F’ 的大写和小写形式也都出现了,但是 ‘R’ 比 ‘F’ 和 ‘A’ 更好。
示例 3:
输入:s = “AbCdEfGhIjK” 输出:“” 解释: 不存在大写和小写形式都出现的字母。

提示:

  • 1 <= s.length <= 1000
  • s 由小写和大写英文字母组成

思路:
模拟

  1. class Solution {
  2. public String greatestLetter(String s) {
  3. boolean[] b1 = new boolean[26];
  4. boolean[] b2 = new boolean[26];
  5. for (int i = 0; i < s.length(); i++) {
  6. char c = s.charAt(i);
  7. if (c >= 'a' && c <= 'z')
  8. b1[c - 'a'] = true;
  9. else
  10. b2[c - 'A'] = true;
  11. }
  12. int idx = -1;
  13. for (int i = 0; i < 26; i++) {
  14. if (b1[i] && b2[i])
  15. idx = i;
  16. }
  17. if (idx == -1) return "";
  18. else return (char)('A' + idx) + "";
  19. }
  20. }
  1. // 更容易的写法
  2. class Solution {
  3. public String greatestLetter(String s) {
  4. for (char a = 'Z'; a >= 'A'; a--) {
  5. if (s.indexOf(a) >= 0 && s.indexOf(a - 'A' + 'a') >= 0)
  6. return a + "";
  7. }
  8. return "";
  9. }
  10. }

5218. 个位数字为 K 的整数之和

给你两个整数 num 和 k ,考虑具有以下属性的正整数多重集:

  • 每个整数个位数字都是 k 。
  • 所有整数之和是 num 。

返回该多重集的最小大小,如果不存在这样的多重集,返回 -1 。
注意:

  • 多重集与集合类似,但多重集可以包含多个同一整数,空多重集的和为 0 。
  • 个位数字 是数字最右边的数位。

示例 1:
输入:num = 58, k = 9 输出:2 解释: 多重集 [9,49] 满足题目条件,和为 58 且每个整数的个位数字是 9 。 另一个满足条件的多重集是 [19,39] 。 可以证明 2 是满足题目条件的多重集的最小长度。
示例 2:
输入:num = 37, k = 2 输出:-1 解释:个位数字为 2 的整数无法相加得到 37 。
示例 3:
输入:num = 0, k = 7 输出:0 解释:空多重集的和为 0 。

提示:

  • 0 <= num <= 3000
  • 0 <= k <= 9

思路:
个位数均相同,考虑[0 - 9]k是否能凑出num的个位数

  1. class Solution {
  2. public int minimumNumbers(int num, int k) {
  3. if (num == 0) return 0;
  4. for (int i = 1; i <= 10; i++) {
  5. if (k * i % 10 == num % 10 && k * i <= num)
  6. return i;
  7. }
  8. return -1;
  9. }
  10. }

6099. 小于等于 K 的最长二进制子序列

给你一个二进制字符串 s 和一个正整数 k 。
请你返回 s 的 最长 子序列,且该子序列对应的 二进制 数字小于等于 k 。
注意:

  • 子序列可以有 前导 0
  • 空字符串视为 0 。
  • 子序列 是指从一个字符串中删除零个或者多个字符后,不改变顺序得到的剩余字符序列。

示例 1:
输入:s = “1001010”, k = 5 输出:5 解释:s 中小于等于 5 的最长子序列是 “00010” ,对应的十进制数字是 2 。 注意 “00100” 和 “00101” 也是可行的最长子序列,十进制分别对应 4 和 5 。 最长子序列的长度为 5 ,所以返回 5 。
示例 2:
输入:s = “00101001”, k = 1 输出:6 解释:“000001” 是 s 中小于等于 1 的最长子序列,对应的十进制数字是 1 。 最长子序列的长度为 6 ,所以返回 6 。

提示:

  • 1 <= s.length <= 1000
  • s[i] 要么是 ‘0’ ,要么是 ‘1’ 。
  • 1 <= k <= 109

思路:
贪心
统计0的次数,倒着考虑哪些1可以加入
时间复杂度:O(n)

  1. class Solution {
  2. public int longestSubsequence(String s, int k) {
  3. int cnt = 0;
  4. int n = s.length();
  5. for (int i = 0; i < n; i++) {
  6. if (s.charAt(i) == '0')
  7. cnt++;
  8. }
  9. long val = 0;
  10. int res = cnt;
  11. for (int i = n - 1; i >= 0; i--) {
  12. if (s.charAt(i) == '1') {
  13. if (n - i > 30 || val + (1 << n - i - 1) > k)
  14. break;
  15. else {
  16. res++;
  17. val |= 1 << (n - i - 1);
  18. }
  19. }
  20. }
  21. return res;
  22. }
  23. }

5254. 卖木头块

给你两个整数 m 和 n ,分别表示一块矩形木块的高和宽。同时给你一个二维整数数组 prices ,其中 prices[i] = [hi, wi, pricei] 表示你可以以 pricei 元的价格卖一块高为 hi 宽为 wi 的矩形木块。
每一次操作中,你必须按下述方式之一执行切割操作,以得到两块更小的矩形木块:

  • 沿垂直方向按高度 完全 切割木块,或
  • 沿水平方向按宽度 完全 切割木块

在将一块木块切成若干小木块后,你可以根据 prices 卖木块。你可以卖多块同样尺寸的木块。你不需要将所有小木块都卖出去。你 不能 旋转切好后木块的高和宽。
请你返回切割一块大小为 _m x n _的木块后,能得到的 最多 钱数。
注意你可以切割木块任意次。

示例 1:
image.png
输入: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 元是最多能得到的钱数。
示例 2:
image.png
输入: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 的木块。

提示:

  • 1 <= m, n <= 200
  • 1 <= prices.length <= 2 * 104
  • prices[i].length == 3
  • 1 <= hi <= m
  • 1 <= wi <= n
  • 1 <= pricei <= 106
  • 所有 (hi, wi) 互不相同

思路:
DP
状态表示:f[i][j]表示高为i,宽为j的木块的最大收益
状态转移:考虑最后一步按行切还是按列切
f[i][j] = Math.max(f[i][j], Math.max(f[i - h][j] + a[h][j], f[i - h][j] + f[h][j]))
f[i][j] = Math.max(f[i][j], Math.max(f[i][j - w] + a[i][w], f[i][j - w] + f[i][w]))

  1. class Solution {
  2. public long sellingWood(int n, int m, int[][] prices) {
  3. final int N = 200;
  4. int[][] a = new int[N + 1][N + 1];
  5. for (int[] p : prices) {
  6. int h = p[0], w = p[1], c = p[2];
  7. a[h][w] = c;
  8. }
  9. long[][] f = new long[n + 1][m + 1];
  10. for (int i = 1; i <= n; i++) {
  11. for (int j = 1; j <= m; j++) {
  12. for (int h = 1; h <= i; h++)
  13. f[i][j] = Math.max(f[i][j], Math.max(f[i - h][j] + a[h][j], f[i - h][j] + f[h][j]));
  14. for (int w = 1; w <= j; w++)
  15. f[i][j] = Math.max(f[i][j], Math.max(f[i][j - w] + a[i][w], f[i][j - w] + f[i][w]));
  16. }
  17. }
  18. return f[n][m];
  19. }
  20. }
  1. // 记忆化
  2. class Solution {
  3. int[][] a = new int[201][201];
  4. long[][] f = new long[201][201];
  5. public long sellingWood(int n, int m, int[][] prices) {
  6. for (int[] p : prices) {
  7. int h = p[0], w = p[1], c = p[2];
  8. a[h][w] = c;
  9. }
  10. for (int i = 1; i <= 200; i++) {
  11. Arrays.fill(f[i], -1);
  12. f[i][0] = 0;
  13. }
  14. return dfs(n, m);
  15. }
  16. long dfs(int n, int m) {
  17. if (f[n][m] != -1)
  18. return f[n][m];
  19. long max = a[n][m];
  20. for (int i = 1; i < n; i++) {
  21. max = Math.max(dfs(i, m) + dfs(n - i, m), max);
  22. max = Math.max(a[i][m] + dfs(n - i, m), max);
  23. }
  24. for (int j = 1; j < m; j++) {
  25. max = Math.max(dfs(n, j) + dfs(n, m - j), max);
  26. max = Math.max(a[n][j] + dfs(n, m - j), max);
  27. }
  28. return (f[n][m] = max);
  29. }
  30. }