《小C的合法k-size字符串问题》和《小U的相似字符串》| 豆包MarsCode AI刷题

129 阅读4分钟

今天我们将在豆包MarsCode AI刷题平台上,完成《小C的合法k-size字符串问题》与《小U的相似字符串》这两个算法问题,通过这些练习提升用户解决此类问题的能力

《小C的合法k-size字符串问题》题面如下:

image.png

问题理解

我们需要计算长度为 n 的、仅由小写字母组成的合法的 k-size 字符串的数量。合法的 k-size 字符串是指它可以被分成恰好 k 段连续的相同字符组成的子串,并且每个连续段的长度至少为2。

数据结构选择

使用一个三维的动态规划数组 f 来存储中间结果。f[i][c][j] 表示长度为 i+1 的字符串,最后一个字符是 c,并且已经分成了 j+1 段的合法字符串的数量。

算法步骤

  1. 初始化

    • 对于长度为1的字符串,每个字符都可以作为初始段,因此 f[0][c][0] = 1
  2. 状态转移

    • 对于每个长度 i,遍历每个可能的最后一个字符 c
    • 对于每个字符 c,遍历前一个字符 prec
    • 如果 cprec 相同,说明当前字符可以继续扩展前一段,因此 f[i][c][j] += f[i-1][c][j]
    • 如果 cprec 不同,并且当前段数 j 大于0,说明可以由前一个字符 prec 的段数 j-1 转移过来,因此 f[i][c][j] += f[i-2][prec][j-1]
  3. 结果计算

    • 最终结果是所有可能的最后一个字符 c 对应的 f[n-2][c][k-1] 的总和。

具体实现

int mod = 1e9+7;

int solution(int n, int k) {
    // write code here
    vector<vector<vector<int>>> f(n,vector<vector<int>>(26,vector<int>(k,0)));
    for(int c=0;c<26;c++){
        f[0][c][0] = 1;
    }
    for(int i = 1;i < n;i++){
        for(int c = 0;c < 26;c++){
            for(int prec = 0;prec < 26;prec++){
                for(int j = 0;j < k;j++){
                    if(c == prec){
                        f[i][c][j] = (f[i][c][j] + f[i-1][c][j])%mod;
                    } else {
                        if(j > 0 && i - 2 >= 0){
                            f[i][c][j] = (f[i][c][j] + f[i-2][prec][j-1])%mod;
                        }
                    }
                    
                }
            }
            
        }
    }
    int ret=0;
    for(int c = 0;c < 26;c++){
        ret = (ret + f[n-2][c][k-1])%mod;
    }
    return ret;
}

《小U的相似字符串》题面如下:

image.png

问题理解

题目要求我们判断给定的 n 个字符串中有多少对是相似的。两个字符串相似的定义是它们包含的每个字母的个数都相等。

数据结构选择

为了判断两个字符串是否相似,我们需要一种方法来表示字符串中每个字母的个数。这里使用一个长度为26的整数数组 vector<int>,其中每个位置对应一个字母,数组的值表示该字母在字符串中出现的次数。

算法步骤

  1. 字符串转换

    • 对于每个字符串,遍历其所有字符,并统计每个字符的出现次数,存储在 vector<int> 中。
  2. 哈希映射

    • 为了快速比较字符串,将每个字符串的字母计数数组转换为一个哈希值。这里使用了 getHash 函数,通过将字母计数数组中的每个值乘以一个基数(26)并取模(1e9+7)来生成一个唯一的哈希值。
  3. 统计相似字符串对

    • 使用一个 map<ll, int> 来存储每个哈希值出现的次数。
    • 对于每个哈希值,如果它出现了 k 次,那么可以形成 k * (k - 1) / 2 对相似字符串。

具体实现

typedef long long ll;

int base=26, mod=1e9+7;
ll getHash(vector<int> num){
    ll ret=0;
    for(int i=0;i<26;i++){
        ret = (ret*base + num[i])%mod;
    }
    return ret;
}

int solution(int n, vector<string> strings) {
    // write code here
    int ret=0;
    map<ll,int> nums;
    for(auto& s : strings){
        vector<int> num(26,0);
        for(char c : s){
            num[c - 'a']++;
        }
        nums[getHash(num)]++;
    }
    for(auto& x : nums){
        ret += x.second * (x.second - 1) / 2;
    }
    return ret;
}

借助豆包MarsCode AI刷题平台,我们不仅高效地解决了《小C的合法k-size字符串问题》和《小U的相似字符串》,还加深了对相关算法和数据结构的理解,后续会借助豆包MarsCode AI给大家展示更多题目的解法。