力扣第383场周赛记录

2946. 循环移位后的矩阵相似检查

右移左移都是k位 所以只需要判断当前 i 位与 i+k 位是否一致 如果有一处不一致 则返回false 反之返回true

class Solution {
public:
    
    bool areSimilar(vector<vector<int>>& mat, int k) {
        int n = mat.size();
        int m = mat[0].size();

        for (int i = 0; i < n; i ++ )
            for (int j = 0; j < m; j ++ )
                if (mat[i][j] != mat[i][(j + k) % m]) return false;

        return true;
    }
     
};


2947. 统计美丽子字符串 I

这题最开始我想的是用前缀和+哈希表来做 写到一半发现好麻烦 最后还是选择用双指针来做...

将字符串从前往后遍历 同时记录元音字符和辅音字符数量 最后直接判断当前元音字符数量和辅音字符数量是否满足条件 满足则答案++

class Solution {
public:
    int beautifulSubstrings(string s, int k) {
        int res = 0;
        for(int i = 0; i < s.size(); i++){
            int vosum = 0, consum = 0;
            for(int j = i; j < s.size(); j ++ ){
                if(s[j]=='a'||s[j]=='e'||s[j]=='i'||s[j]=='o'||s[j]=='u') vosum ++;
                else consum++ ;
                if((vosum * consum) % k == 0 && vosum == consum) res ++;
            }
        }
        return res;
    }
};

2948. 交换得到字典序最小的数组

解法不唯一 在这里写两种

多路并归+二分

先将数组排序  排序后的数组记为temp  然后将数组分为不同的组  用一个下标数组分别指向不同组的最小值的下标  遍历nums数组  用两次二分找到当前数所在的组  数组c记录了该组中的最小值下标的增量  最后就可以通过idx和c数组从temp数组中找到对应的值写入答案中

class Solution {
public:
    vector<int> lexicographicallySmallestArray(vector<int>& nums, int limit) {
        int n = nums.size();
        vector<int> temp = nums;
        sort(temp.begin(), temp.end());
        vector<int> idx;
        idx.push_back(0);
        for(int i = 1; i < n; i++ ){
            if(abs(temp[i] - temp[i - 1]) > limit){
                idx.push_back(i);
            }
        }
        int m = idx.size();
        vector<int> c(m,0);
        for(int i = 0; i < n; i++ ){
            //两次二分找到nums[i]所在的组
            int j = upper_bound(temp.begin(), temp.end(), nums[i]) - temp.begin();
            int k = lower_bound(idx.begin(), idx.end(), j) - idx.begin();
            nums[i] = temp[idx[k - 1] + c[k - 1]];
            //当前组的最小值下标往后移一位
            c[k - 1]++;
        }
        return nums;
    }
};

并查集+分组排序

先将数组排序  排序后的数组记为temp  然后将数组用并查集分为不同的组  用哈希表(数组)来映射到原数组的下标  最后将不同的组进行排序写入答案。

class Solution {
public:
    vector<int> lexicographicallySmallestArray(vector<int>& nums, int limit) {
        int n = nums.size();
        UnionFind uf(n);
        vector<pair<int, int>> a;
        for(int i = 0; i < n; i++ ){
            a.push_back({nums[i], i});
        }
        sort(a.begin(), a.end());
        // 用并查集来进行分组
        for(int i = 1; i < n; i++ ){
            if(a[i].first - a[i-1].first <= limit){
                uf.Union(a[i-1].second, a[i].second);
            }
        }
        // 用哈希表(数组)来映射到原数组的下标
        vector<vector<int>> groups(n);
        for(int i = 0; i < n; i++ ){
            int key = uf.Find(i);
            groups[key].push_back(i);
        }
        // 对每个组的元素进行排序并替换回原始数组
        for(int i = 0; i < n; i++ ){
            if(groups[i].empty()){
                continue;
            }
            int key = uf.Find(i);
            vector<int> temp2;
            for(int x : groups[i]){
                temp2.push_back(nums[x]);
            }
            sort(temp2.begin(), temp2.end());
            int j = 0;
            for(int x : groups[i]){
                nums[x] = temp2[j ++];
            }
        }
        return nums;
    }
};

2949. 统计美丽子字符串 II

最后一题有思路 没写出来

补题解

分解质因子+前缀和+哈希表

class Solution {
    int p_sqrt(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;
    }

    const int AEIOU_MASK = 1065233;

public:
    long long beautifulSubstrings(string s, int k) {
        k = p_sqrt(k * 4);
        // 把 pair 压缩成 long long(或者 int)就可以用 umap 了
        map<pair<int, int>, int> cnt;
        cnt[{k - 1, 0}]++; // 添加 (k-1, sum)
        long long ans = 0;
        int sum = 0;
        for (int i = 0; i < s.length(); i++) {
            int bit = (AEIOU_MASK >> (s[i] - 'a')) & 1;
            sum += bit * 2 - 1; // 1 -> 1    0 -> -1
            ans += cnt[{i % k, sum}]++;
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值