image.png
还行,就是前面急了,wrong了两次

5976. 检查是否每一行每一列都包含全部整数

对一个大小为 n x n 的矩阵而言,如果其每一行和每一列都包含从 1 到 n 的 全部 整数(含 1 和 n),则认为该矩阵是一个 有效 矩阵。
给你一个大小为 n x n 的整数矩阵 matrix ,请你判断矩阵是否为一个有效矩阵:如果是,返回 true ;否则,返回 false 。

示例 1:
image.png
输入:matrix = [[1,2,3],[3,1,2],[2,3,1]] 输出:true 解释:在此例中,n = 3 ,每一行和每一列都包含数字 1、2、3 。 因此,返回 true 。
示例 2:
image.png
输入:matrix = [[1,1,1],[1,2,3],[1,2,3]] 输出:false 解释:在此例中,n = 3 ,但第一行和第一列不包含数字 2 和 3 。 因此,返回 false 。

提示:

  • n == matrix.length == matrix[i].length
  • 1 <= n <= 100
  • 1 <= matrix[i][j] <= n

思路:
简单模拟一下

  1. class Solution {
  2. public boolean checkValid(int[][] matrix) {
  3. int n = matrix.length;
  4. boolean[] st = new boolean[n + 1];
  5. for (int i = 0; i < n; i++) {
  6. Arrays.fill(st, false);
  7. for (int j = 0; j < n; j++)
  8. st[matrix[i][j]] = true;
  9. for (int j = 1; j <= n; j++)
  10. if (!st[j]) return false;
  11. }
  12. for (int j = 0; j < n; j++) {
  13. Arrays.fill(st, false);
  14. for (int i = 0; i < n; i++)
  15. st[matrix[i][j]] = true;
  16. for (int i = 1; i <= n; i++)
  17. if (!st[i]) return false;
  18. }
  19. return true;
  20. }
  21. }

5977. 最少交换次数来组合所有的 1 II

交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。
环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻
给你一个 二进制环形 数组 nums ,返回在 任意位置 将数组中的所有 1 聚集在一起需要的最少交换次数。

示例 1:
输入:nums = [0,1,0,1,1,0,0] 输出:1 解释:这里列出一些能够将所有 1 聚集在一起的方案: [0,0,1,1,1,0,0] 交换 1 次。 [0,1,1,1,0,0,0] 交换 1 次。 [1,1,0,0,0,0,1] 交换 2 次(利用数组的环形特性)。 无法在交换 0 次的情况下将数组中的所有 1 聚集在一起。 因此,需要的最少交换次数为 1 。
示例 2:
输入:nums = [0,1,1,1,0,0,1,1,0] 输出:2 解释:这里列出一些能够将所有 1 聚集在一起的方案: [1,1,1,0,0,0,0,1,1] 交换 2 次(利用数组的环形特性)。 [1,1,1,1,1,0,0,0,0] 交换 2 次。 无法在交换 0 次或 1 次的情况下将数组中的所有 1 聚集在一起。 因此,需要的最少交换次数为 2 。
示例 3:
输入:nums = [1,1,0,0,1] 输出:0 解释:得益于数组的环形特性,所有的 1 已经聚集在一起。 因此,需要的最少交换次数为 0 。

提示:

  • 1 <= nums.length <= 105
  • nums[i] 为 0 或者 1

思路:破环成链 + 前缀和
统计1的总数作为滑窗大小,找到最大的滑窗

注意:如果1的个数为0,小心越界!

  1. class Solution {
  2. public int minSwaps(int[] nums) {
  3. int cnt = 0, n = nums.length;
  4. for (int i = 0; i < n; i++)
  5. if (nums[i] == 1) cnt++;
  6. if (cnt == 0) return 0;
  7. int[] a = new int[2 * n];
  8. for (int i = 0; i < n; i++)
  9. a[i] = a[i + n] = nums[i];
  10. int max = 0;
  11. for (int i = 1; i < 2 * n; i++)
  12. a[i] += a[i - 1];
  13. max = a[cnt - 1];
  14. for (int i = cnt; i < 2 * n; i++)
  15. max = Math.max(max, a[i] - a[i - cnt]);
  16. return cnt - max;
  17. }
  18. }

5978. 统计追加字母可以获得的单词数

给你两个下标从 0 开始的字符串数组 startWords 和 targetWords 。每个字符串都仅由 小写英文字母 组成。
对于 targetWords 中的每个字符串,检查是否能够从 startWords 中选出一个字符串,执行一次 转换操作 ,得到的结果与当前 targetWords 字符串相等。
转换操作 如下面两步所述:

  1. 追加 任何 不存在 于当前字符串的任一小写字母到当前字符串的末尾。
    • 例如,如果字符串为 “abc” ,那么字母 ‘d’、’e’ 或 ‘y’ 都可以加到该字符串末尾,但 ‘a’ 就不行。如果追加的是 ‘d’ ,那么结果字符串为 “abcd” 。
  2. 重排 新字符串中的字母,可以按 任意 顺序重新排布字母。
    • 例如,”abcd” 可以重排为 “acbd”、”bacd”、”cbda”,以此类推。注意,它也可以重排为 “abcd” 自身。

找出 targetWords 中有多少字符串能够由 startWords 中的 任一 字符串执行上述转换操作获得。返回 _targetWords _中这类 字符串的数目
注意:你仅能验证 targetWords 中的字符串是否可以由 startWords 中的某个字符串经执行操作获得。startWords 中的字符串在这一过程中 发生实际变更。

示例 1:
输入:startWords = [“ant”,”act”,”tack”], targetWords = [“tack”,”act”,”acti”] 输出:2 解释: - 为了形成 targetWords[0] = “tack” ,可以选用 startWords[1] = “act” ,追加字母 ‘k’ ,并重排 “actk” 为 “tack” 。 - startWords 中不存在可以用于获得 targetWords[1] = “act” 的字符串。 注意 “act” 确实存在于 startWords ,但是 必须 在重排前给这个字符串追加一个字母。 - 为了形成 targetWords[2] = “acti” ,可以选用 startWords[1] = “act” ,追加字母 ‘i’ ,并重排 “acti” 为 “acti” 自身。
示例 2:
输入:startWords = [“ab”,”a”], targetWords = [“abc”,”abcd”] 输出:1 解释: - 为了形成 targetWords[0] = “abc” ,可以选用 startWords[0] = “ab” ,追加字母 ‘c’ ,并重排为 “abc” 。 - startWords 中不存在可以用于获得 targetWords[1] = “abcd” 的字符串。

提示:

  • 1 <= startWords.length, targetWords.length <= 5 * 104
  • 1 <= startWords[i].length, targetWords[j].length <= 26
  • startWords 和 targetWords 中的每个字符串都仅由小写英文字母组成
  • 在 startWords 或 targetWords 的任一字符串中,每个字母至多出现一次

思路:
注意题意是两个转换操作都得执行
用字典树存储startWords数组中的每一个字符串转换后的所有串,按从小到大的字母顺序
查询targetWords中的串排序后是否在字典树中出现即可

  1. class Solution {
  2. public int wordCount(String[] s, String[] t) {
  3. int n = t.length;
  4. Trie trie = new Trie();
  5. for (String ss : s) {
  6. trie.insert(ss);
  7. }
  8. int cnt = 0;
  9. for (String ss : t) {
  10. if (trie.query(ss))
  11. cnt++;
  12. }
  13. return cnt;
  14. }
  15. }
  16. class Trie {
  17. class TrieNode {
  18. TrieNode[] son = new TrieNode[26];
  19. boolean end;
  20. }
  21. TrieNode root = new TrieNode();
  22. void insert(String s) {
  23. char[] ch = s.toCharArray();
  24. boolean[] st = new boolean[26];
  25. for (char c : ch)
  26. st[c - 'a'] = true;
  27. char[] cc = new char[ch.length + 1];
  28. int len = ch.length;
  29. for (int i = 0; i < 26; i++) {
  30. if (!st[i]) {
  31. System.arraycopy(ch, 0, cc, 0, ch.length);
  32. cc[len] = (char)(i + 'a');
  33. Arrays.sort(cc);
  34. insert(cc);
  35. }
  36. }
  37. }
  38. void insert(char[] ch) {
  39. TrieNode cur = root;
  40. for (int i = 0; i < ch.length; i++) {
  41. int idx = ch[i] - 'a';
  42. if (cur.son[idx] == null)
  43. cur.son[idx] = new TrieNode();
  44. cur = cur.son[idx];
  45. }
  46. cur.end = true;
  47. }
  48. boolean query(String s) {
  49. char[] ch = s.toCharArray();
  50. Arrays.sort(ch);
  51. TrieNode cur = root;
  52. for (int i = 0; i < ch.length; i++) {
  53. int idx = ch[i] - 'a';
  54. if (cur.son[idx] == null) {
  55. return false;
  56. }
  57. cur = cur.son[idx];
  58. }
  59. return cur.end;
  60. }
  61. }

5979. 全部开花的最早一天

image.pngimage.png
你有 n 枚花的种子。每枚种子必须先种下,才能开始生长、开花。播种需要时间,种子的生长也是如此。给你两个下标从 0 开始的整数数组 plantTime 和 growTime ,每个数组的长度都是 n :

  • plantTime[i] 是 播种 第 i 枚种子所需的 完整天数 。每天,你只能为播种某一枚种子而劳作。无须 连续几天都在种同一枚种子,但是种子播种必须在你工作的天数达到 plantTime[i] 之后才算完成。
  • growTime[i] 是第 i 枚种子完全种下后生长所需的 完整天数 。在它生长的最后一天 之后 ,将会开花并且永远 绽放

从第 0 开始,你可以按 任意 顺序播种种子。
返回所有种子都开花的 最早 一天是第几天。

示例 1:
输入:plantTime = [1,4,3], growTime = [2,3,1] 输出:9 解释:灰色的花盆表示播种的日子,彩色的花盆表示生长的日子,花朵表示开花的日子。 一种最优方案是: 第 0 天,播种第 0 枚种子,种子生长 2 整天。并在第 3 天开花。 第 1、2、3、4 天,播种第 1 枚种子。种子生长 3 整天,并在第 8 天开花。 第 5、6、7 天,播种第 2 枚种子。种子生长 1 整天,并在第 9 天开花。 因此,在第 9 天,所有种子都开花。
示例 2:
输入:plantTime = [1,2,3,2], growTime = [2,1,2,1] 输出:9 解释:灰色的花盆表示播种的日子,彩色的花盆表示生长的日子,花朵表示开花的日子。 一种最优方案是: 第 1 天,播种第 0 枚种子,种子生长 2 整天。并在第 4 天开花。 第 0、3 天,播种第 1 枚种子。种子生长 1 整天,并在第 5 天开花。 第 2、4、5 天,播种第 2 枚种子。种子生长 2 整天,并在第 8 天开花。 第 6、7 天,播种第 3 枚种子。种子生长 1 整天,并在第 9 天开花。 因此,在第 9 天,所有种子都开花。
示例 3:
输入:plantTime = [1], growTime = [1] 输出:2 解释:第 0 天,播种第 0 枚种子。种子需要生长 1 整天,然后在第 2 天开花。 因此,在第 2 天,所有种子都开花。

提示:

  • n == plantTime.length == growTime.length
  • 1 <= n <= 105
  • 1 <= plantTime[i], growTime[i] <= 104

思路:
贪心题
种树时间是必须全部累加,所以只需要按成长时间从大到小排就行了,然后扫描一遍,找到最大开花时间

  1. class Solution {
  2. public int earliestFullBloom(int[] p, int[] g) {
  3. int n = p.length;
  4. int[][] a = new int[n][2];
  5. for (int i = 0; i < n; i++) {
  6. a[i][0] = p[i];
  7. a[i][1] = g[i];
  8. }
  9. Arrays.sort(a, (o1, o2) -> (o2[1] - o1[1]));
  10. int max = 0;
  11. int cnt = 0;
  12. for (int i = 0; i < n; i++) {
  13. max = Math.max(a[i][0] + a[i][1] + cnt, max);
  14. cnt += a[i][0];
  15. }
  16. return max;
  17. }
  18. }