文章目录
- 周赛373
- [2946. 循环移位后的矩阵相似检查](https://leetcode.cn/problems/matrix-similarity-after-cyclic-shifts/)
- [2947. 统计美丽子字符串 I](https://leetcode.cn/problems/count-beautiful-substrings-i/)
- [2948. 交换得到字典序最小的数组](https://leetcode.cn/problems/make-lexicographically-smallest-array-by-swapping-elements/)
- [2949. 统计美丽子字符串 II](https://leetcode.cn/problems/count-beautiful-substrings-ii/)
周赛373
2946. 循环移位后的矩阵相似检查
简单
给你一个大小为 m x n
的整数矩阵 mat
和一个整数 k
。请你将矩阵中的 奇数 行循环 右 移 k
次,偶数 行循环 左 移 k
次。
如果初始矩阵和最终矩阵完全相同,则返回 true
,否则返回 false
。
示例 1:
输入:mat = [[1,2,1,2],[5,5,5,5],[6,3,6,3]], k = 2
输出:true
解释:
初始矩阵如图一所示。
图二表示对奇数行右移一次且对偶数行左移一次后的矩阵状态。
图三是经过两次循环移位后的最终矩阵状态,与初始矩阵相同。
因此,返回 true 。
示例 2:
输入:mat = [[2,2],[2,2]], k = 3
输出:true
解释:由于矩阵中的所有值都相等,即使进行循环移位,矩阵仍然保持不变。因此,返回 true 。
示例 3:
输入:mat = [[1,2]], k = 1
输出:false
解释:循环移位一次后,mat = [[2,1]],与初始矩阵不相等。因此,返回 false 。
提示:
1 <= mat.length <= 25
1 <= mat[i].length <= 25
1 <= mat[i][j] <= 25
1 <= k <= 50
模拟
class Solution {
public boolean areSimilar(int[][] mat, int k) {
int m = mat.length, n = mat[0].length;
while(k > n) k -= n;
int flag = 1;
for(int i = 0; i < m; i++){
for(int j = 0; j < n; j++){
if(mat[i][j] != mat[i][(j + flag * (k) + n) % n])
return false;
}
flag = -flag;
}
return true;
}
}
2947. 统计美丽子字符串 I
提示
中等
0
相关企业
给你一个字符串 s
和一个正整数 k
。
用 vowels
和 consonants
分别表示字符串中元音字母和辅音字母的数量。
如果某个字符串满足以下条件,则称其为 美丽字符串 :
vowels == consonants
,即元音字母和辅音字母的数量相等。(vowels * consonants) % k == 0
,即元音字母和辅音字母的数量的乘积能被k
整除。
返回字符串 s
中 非空美丽子字符串 的数量。
子字符串是字符串中的一个连续字符序列。
英语中的 元音字母 为 'a'
、'e'
、'i'
、'o'
和 'u'
。
英语中的 辅音字母 为除了元音字母之外的所有字母。
示例 1:
输入:s = "baeyh", k = 2
输出:2
解释:字符串 s 中有 2 个美丽子字符串。
- 子字符串 "baeyh",vowels = 2(["a","e"]),consonants = 2(["y","h"])。
可以看出字符串 "aeyh" 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
- 子字符串 "baeyh",vowels = 2(["a","e"]),consonants = 2(["b","y"])。
可以看出字符串 "baey" 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
可以证明字符串 s 中只有 2 个美丽子字符串。
示例 2:
输入:s = "abba", k = 1
输出:3
解释:字符串 s 中有 3 个美丽子字符串。
- 子字符串 "abba",vowels = 1(["a"]),consonants = 1(["b"])。
- 子字符串 "abba",vowels = 1(["a"]),consonants = 1(["b"])。
- 子字符串 "abba",vowels = 2(["a","a"]),consonants = 2(["b","b"])。
可以证明字符串 s 中只有 3 个美丽子字符串。
示例 3:
输入:s = "bcdf", k = 1
输出:0
解释:字符串 s 中没有美丽子字符串。
提示:
1 <= s.length <= 1000
1 <= k <= 1000
s
仅由小写英文字母组成。
前缀和 + 暴力枚举
class Solution {
/**
统计子数组 元音和辅音的出现次数
然后枚举所有子数组
*/
public int beautifulSubstrings(String s, int k) {
int n = s.length();
int[] prev = new int[n+1];
int[] prec = new int[n+1];
for(int i = 0; i < n; i++){
prev[i+1] = prev[i] + (check(s.charAt(i)) ? 1 : 0);
prec[i+1] = prec[i] + (check(s.charAt(i)) ? 0 : 1);
}
int res = 0;
for(int i = 1; i <= n; i++){
for(int j = i+1; j <= n; j++){
int vowel = prev[j] - prev[i-1];
int cons = prec[j] - prec[i-1];
if(vowel == cons && (vowel*cons)%k == 0)
res += 1;
}
}
return res;
}
public boolean check(char c){
return c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u';
}
}
2948. 交换得到字典序最小的数组
中等
给你一个下标从 0 开始的 正整数 数组 nums
和一个 正整数 limit
。
在一次操作中,你可以选择任意两个下标 i
和 j
,如果 满足 |nums[i] - nums[j]| <= limit
,则交换 nums[i]
和 nums[j]
。
返回执行任意次操作后能得到的 字典序最小的数组 。
如果在数组 a
和数组 b
第一个不同的位置上,数组 a
中的对应字符比数组 b
中的对应字符的字典序更小,则认为数组 a
就比数组 b
字典序更小。例如,数组 [2,10,3]
比数组 [10,2,3]
字典序更小,下标 0
处是两个数组第一个不同的位置,且 2 < 10
。
示例 1:
输入:nums = [1,5,3,9,8], limit = 2
输出:[1,3,5,8,9]
解释:执行 2 次操作:
- 交换 nums[1] 和 nums[2] 。数组变为 [1,3,5,9,8] 。
- 交换 nums[3] 和 nums[4] 。数组变为 [1,3,5,8,9] 。
即便执行更多次操作,也无法得到字典序更小的数组。
注意,执行不同的操作也可能会得到相同的结果。
示例 2:
输入:nums = [1,7,6,18,2,1], limit = 3
输出:[1,6,7,18,1,2]
解释:执行 3 次操作:
- 交换 nums[1] 和 nums[2] 。数组变为 [1,6,7,18,2,1] 。
- 交换 nums[0] 和 nums[4] 。数组变为 [2,6,7,18,1,1] 。
- 交换 nums[0] 和 nums[5] 。数组变为 [1,6,7,18,1,2] 。
即便执行更多次操作,也无法得到字典序更小的数组。
示例 3:
输入:nums = [1,7,28,19,10], limit = 3
输出:[1,7,28,19,10]
解释:[1,7,28,19,10] 是字典序最小的数组,因为不管怎么选择下标都无法执行操作。
提示:
1 <= nums.length <= 105
1 <= nums[i] <= 109
1 <= limit <= 109
排序 + 分组循环
https://leetcode.cn/problems/make-lexicographically-smallest-array-by-swapping-elements/solutions/2542762/pai-xu-fen-zu-xun-huan-pythonjavacgo-by-pbfey/
class Solution {
/**
把nums排序后,需要找到一个最长的连续段,相邻的数组差<=limit
这一整段对应的下标集合,这些位置是可以排序的
*/
public int[] lexicographicallySmallestArray(int[] nums, int limit) {
int n = nums.length;
Integer[] ids = new Integer[n];
for (int i = 0; i < n; i++) {
ids[i] = i;
}
Arrays.sort(ids, (i, j) -> nums[i] - nums[j]);
// ids[i]不是有序的,但是nums[ids[i]]是有序的
int[] ans = new int[n];
for (int i = 0; i < n; ) {
int st = i;
i++;
while(i < n && nums[ids[i]] - nums[ids[i-1]] <= limit)
i++;
Integer[] subIds = Arrays.copyOfRange(ids, st, i);
Arrays.sort(subIds);
for (int j = 0; j < subIds.length; j++) {
ans[subIds[j]] = nums[ids[st + j]];
}
}
return ans;
}
}
2949. 统计美丽子字符串 II
困难
给你一个字符串 s
和一个正整数 k
。
用 vowels
和 consonants
分别表示字符串中元音字母和辅音字母的数量。
如果某个字符串满足以下条件,则称其为 美丽字符串 :
vowels == consonants
,即元音字母和辅音字母的数量相等。(vowels * consonants) % k == 0
,即元音字母和辅音字母的数量的乘积能被k
整除。
返回字符串 s
中 非空美丽子字符串 的数量。
子字符串是字符串中的一个连续字符序列。
英语中的 元音字母 为 'a'
、'e'
、'i'
、'o'
和 'u'
。
英语中的 辅音字母 为除了元音字母之外的所有字母。
示例 1:
输入:s = "baeyh", k = 2
输出:2
解释:字符串 s 中有 2 个美丽子字符串。
- 子字符串 "baeyh",vowels = 2(["a","e"]),consonants = 2(["y","h"])。
可以看出字符串 "aeyh" 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
- 子字符串 "baeyh",vowels = 2(["a","e"]),consonants = 2(["b","y"])。
可以看出字符串 "baey" 是美丽字符串,因为 vowels == consonants 且 vowels * consonants % k == 0 。
可以证明字符串 s 中只有 2 个美丽子字符串。
示例 2:
输入:s = "abba", k = 1
输出:3
解释:字符串 s 中有 3 个美丽子字符串。
- 子字符串 "abba",vowels = 1(["a"]),consonants = 1(["b"])。
- 子字符串 "abba",vowels = 1(["a"]),consonants = 1(["b"])。
- 子字符串 "abba",vowels = 2(["a","a"]),consonants = 2(["b","b"])。
可以证明字符串 s 中只有 3 个美丽子字符串。
示例 3:
输入:s = "bcdf", k = 1
输出:0
解释:字符串 s 中没有美丽子字符串。
提示:
1 <= s.length <= 5 * 104
1 <= k <= 1000
s
仅由小写英文字母组成。
质因数分解 + 前缀和 + 哈希表
https://leetcode.cn/problems/count-beautiful-substrings-ii/solutions/2542274/fen-jie-zhi-yin-zi-qian-zhui-he-ha-xi-bi-ceil/
class Solution {
/**
转化:把元音看作1,辅音看作-1
「元音字母和辅音字母的数量相等」就等价于:找到一个和为 0 的连续子数组。注意这种子数组的长度一定是偶数,因为元音辅音数量相等。
设子数组长度为L,那么元音辅音数量都等于L/2
所以「元音字母和辅音字母的数量的乘积能被 kkk 整除」等价于 (L/2)^2 mod k = 0
==> L^2 mod 4k = 0 如何去掉平方?
如果一个数 L 的平方能被 n 整除,意味着什么?
*/
private static final int AEIOU_MASK = 1065233;
public long beautifulSubstrings(String s, int k) {
k = pSqrt(k * 4);
Map<Integer, Integer> cnt = new HashMap<>();
int n = s.length();
int sum = n; // 保证非负
cnt.put((k - 1) << 16 | sum, 1); // 添加 (k-1, sum)
long ans = 0;
for (int i = 0; i < n; i++) {
int bit = (AEIOU_MASK >> (s.charAt(i) - 'a')) & 1;
sum += bit * 2 - 1; // 1 -> 1 0 -> -1
ans += cnt.merge((i % k) << 16 | sum, 1, Integer::sum) - 1; // ans += cnt[(i%k,sum)]++
}
return ans;
}
private int pSqrt(int n) {
int res = 1;
for (int i = 2; i * i <= n; i++) {
int i2 = i * i;
while (n % i2 == 0) {
res *= i;
n /= i2;
}
if (n % i == 0) {
res *= i;
n /= i;
}
}
if (n > 1) {
res *= n;
}
return res;
}
}