给你三个整数 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的数量,然后总数量乘以二即可。

392

被折叠的 条评论
为什么被折叠?



