【状态机DP】力扣2745. 构造最长的新字符串

给你三个整数 x ,y 和 z 。

这三个整数表示你有 x 个 “AA” 字符串,y 个 “BB” 字符串,和 z 个 “AB” 字符串。你需要选择这些字符串中的部分字符串(可以全部选择也可以一个都不选择),将它们按顺序连接得到一个新的字符串。新字符串不能包含子字符串 “AAA” 或者 “BBB” 。

请你返回 新字符串的最大可能长度。

子字符串 是一个字符串中一段连续 非空 的字符序列。

示例 1:
输入:x = 2, y = 5, z = 1
输出:12
解释: 我们可以按顺序连接 “BB” ,“AA” ,“BB” ,“AA” ,“BB” 和 “AB” ,得到新字符串 “BBAABBAABBAB” 。
字符串长度为 12 ,无法得到一个更长的符合题目要求的字符串。

示例 2:
输入:x = 3, y = 2, z = 2
输出:14
解释:我们可以按顺序连接 “AB” ,“AB” ,“AA” ,“BB” ,“AA” ,“BB” 和 “AA” ,得到新字符串 “ABABAABBAABBAA” 。
字符串长度为 14 ,无法得到一个更长的符合题目要求的字符串。

提示:
1 <= x, y, z <= 50


记忆化搜索

class Solution {
public:
    int longestString(int x, int y, int z) {
        // x 表示还剩多少个 "AA" 字符串可以使用。
        // y 表示还剩多少个 "BB" 字符串可以使用。
        // z 表示还剩多少个 "AB" 字符串可以使用。
        // k 代表前一个选择:
        // k == 0 表示上一个字符串选择的是 "AA"。
        // k == 1 表示上一个字符串选择的是 "BB"。
        // k == 2 表示上一个字符串选择的是 "AB"。
        int memo[x+1][y+1][z+1][3];
        memset(memo, -1, sizeof(memo));
        function<int(int,int,int,int)> dfs = [&](int x, int y, int z, int k) -> int{
            if(memo[x][y][z][k] != -1) return memo[x][y][z][k];
            int res = 0;
            if(k == 0){
                if(y > 0){
                    res = dfs(x, y-1, z, 1) + 2;
                }
            }
            else{
                if(x > 0){
                    res = dfs(x-1, y, z, 0) + 2;
                }
                if(z > 0){
                    res = max(res, dfs(x, y, z-1, 2)+2);
                }
            }
            memo[x][y][z][k] = res;
            return res;
        };
        return max(dfs(x, y, z, 0), dfs(x, y, z, 1));
    }
};

时间复杂度:O(x∗y∗z)
空间复杂度:O(x * y * z)(主要是 memo 数组的空间消耗)
我们定义一个四维数组memo[x+1][y+1][z+1][3],然后所有值初始化为-1,用于记忆化搜索,避免重复运算。
然后是记忆化搜索的主题函数dfs,我们定义:
// x 表示还剩多少个 “AA” 字符串可以使用。
// y 表示还剩多少个 “BB” 字符串可以使用。
// z 表示还剩多少个 “AB” 字符串可以使用。
// k 代表前一个选择:
// k == 0 表示上一个字符串选择的是 “AA”。
// k == 1 表示上一个字符串选择的是 “BB”。
// k == 2 表示上一个字符串选择的是 “AB”。

我们定义一个res 局部变量,用于存储当前递归状态下计算出的结果。
当上一个状态为AA的时候,那么此时只能加入BB在AA后面,所以res = dfs(x, y-1, z, 1) + 2;,如果当上一个状态不是AA,是BB或者AB的时候,那么后面可以跟AA或AB,对应res = dfs(x-1, y, z, 0) + 2;res = max(res, dfs(x, y, z-1, 2)+2);

最后返回以AA或者BB开头的dfs即可。

贪心算法

class Solution {
public:
    int longestString(int x, int y, int z) {
        return (min(x, y) * 2 + (x != y) + z) * 2;
    }
};

时间复杂度:O(1)。
空间复杂度:O(1)。

如果没有 AB,那么 AA 和 BB 只能交替连接,
如果有 AB,它可以与自身连接,且只能插在 BB 和 AA 之间,即 BB + (ABABAB…) + AA。

或者接在后缀 BB 之后,或者加到前缀 AA 之前。
所以 AB 不会改变 AA 和 BB 交替连接的上限。

所以在代码中,AA和BB交替连接取决于他们最小的个数是哪个,并且如果AA数量不等于BB数量,那么可以有AABBAA或BBAABB这样的交替,所以要加一。最后再加上AB的数量,然后总数量乘以二即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值