周赛373(模拟、前缀和、排序+分组循环、质因数分解+前缀和+哈希表)

文章目录

  • 周赛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

vowelsconsonants 分别表示字符串中元音字母和辅音字母的数量。

如果某个字符串满足以下条件,则称其为 美丽字符串

  • 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

在一次操作中,你可以选择任意两个下标 ij如果 满足 |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

vowelsconsonants 分别表示字符串中元音字母和辅音字母的数量。

如果某个字符串满足以下条件,则称其为 美丽字符串

  • 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;
    }
}

你可能感兴趣的:(#,LC周赛,算法刷题记录,散列表,数据结构)