蓝桥省赛 密码脱落 暴搜 记忆化搜索 区间DP
🍑 算法题解专栏
输入
ABDCDCBABC
输出
3
👨🏫 子序列 和 子串
🍤 串:连续
🍤 序列:允许不连续
🍑 记忆化搜索版
🍤 找不匹配的字符
import java.util.Scanner;
public class Main
{
static int N = 1010;
static String s;
static int[][] f = new int[N][N];//记忆表
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
s = sc.next();
System.out.println(dfs(0, s.length() - 1));
}
// 返回 在 l-r 区间内,需要添加多少个字符才能使得字符串变成回文序列
private static int dfs(int l, int r)
{
if (f[l][r] != 0)
return f[l][r];
if (l >= r)
return 0;
int res;
if (s.charAt(l) != s.charAt(r)) // 只要不匹配,则需要加一个使得它匹配
// 添加一个右字符 添加左字符
res = Math.min(dfs(l, r - 1) + 1, dfs(l + 1, r) + 1);
else
{
// 相等 即 回文 无需处理 --> 跳过
res = dfs(l + 1, r - 1);
}
return f[l][r] = res;//记忆化搜索
}
}
🍑 区间DP版
🍤 求区间内的最大回文子序列
import java.util.Scanner;
public class Main
{
static int N = 1010;
static String s;
static int[][] f = new int[N][N];
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
s = sc.next();
int n = s.length();
for (int len = 1; len <= n; len++)// 枚举区间长度(大区间必定依赖与小区间来求解)
for (int i = 0; i + len - 1 < n; i++)// 枚举左端点
{
int j = i + len - 1;// 计算右端点
if (len == 1)
f[i][j] = 1;
else
{
// f[i][j-1] 和 f[i+1][j] 的最大值 已经包含了 f[l+1][r-1]的最值
//
f[i][j] = Math.max(f[i][j - 1], f[i + 1][j]);
if (s.charAt(i) == s.charAt(j))
f[i][j] = Math.max(f[i][j], f[i + 1][j - 1] + 2);
}
}
int t = f[0][n - 1];// 这个是最大回文子序列
System.out.println(n - t);
}
}
👨🏫 参考题解