问题描述
小S有一个由字符 'U'
和 'C'
组成的字符串 SS,并希望在编辑距离不超过给定值 mm 的条件下,尽可能多地在字符串中找到 "UCC"
子串。
编辑距离定义为将字符串 SS 转化为其他字符串时所需的最少编辑操作次数。允许的每次编辑操作是插入、删除或替换单个字符。你需要计算在给定的编辑距离限制 mm 下,能够包含最多 "UCC"
子串的字符串可能包含多少个这样的子串。
例如,对于字符串"UCUUCCCCC"
和编辑距离限制m = 3
,可以通过编辑字符串生成最多包含3个"UCC"
子串的序列。
约束条件:
- 字符串长度不超过1000
测试样例
样例1:
输入:
m = 3,s = "UCUUCCCCC"
输出:3
样例2:
输入:
m = 6,s = "U"
输出:2
样例3:
输入:
m = 2,s = "UCCUUU"
输出:2
解释
样例1:可以将字符串修改为 "UCCUCCUCC"(2 次替换操作,不超过给定值 m = 3),包含 3 个 "UCC" 子串。
样例2:后面插入 5 个字符 "CCUCC"(5 次插入操作,不超过给定值 m = 6),可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。
样例3:替换最后 2 个字符,可以将字符串修改为 "UCCUCC",包含 2 个 "UCC" 子串。
代码:
public class Main {
public static int solution(int m, String s) {
int n = s.length();
boolean[] used = new boolean[n];
int cnt = 0;
int ans = 0;
// 找到现有的UCC子串
for (int i = 2; i < n; i++) {
if (s.substring(i - 2, i + 1).equals("UCC")) {
used[i] = used[i - 1] = used[i - 2] = true;
cnt += 3;
ans++;
}
}
// 找到未使用的UC子串或者CC子串
for (int i = 1; i < n; i++) {
if (!used[i] && !used[i - 1] && m > 0) {
String t = s.substring(i - 1, i + 1);
if (t.equals("UC") || t.equals("CC")) {
used[i] = used[i - 1] = true;
cnt += 2;
ans++;
m--;
}
}
}
// 处理剩下的单个字符
ans += Math.min(m / 2, n - cnt);
m -= Math.min(m / 2, n - cnt) * 2;
// 如果还有编辑次数大于2,将其分成3个字符一组,相当加入一组UCC字符串
if (m > 2) {
ans += m / 3;
}
//返回结果
return ans;
}
public static void main(String[] args) {
System.out.println(solution(3, "UCUUCCCCC") == 3);
System.out.println(solution(6, "U") == 2);
System.out.println(solution(2, "UCCUUU") == 2);
}
}
代码解释:
类和方法定义:
public class Main {
public static int solution(int m, String s) {
// 函数体
}
public static void main(String[] args) {
// 函数体
}
}
public class Main
:定义了一个名为Main
的公共类。public static int solution(int m, String s)
:定义了一个名为solution
的静态方法,它接收一个整数m
和一个字符串s
作为参数,并返回一个整数结果。public static void main(String[] args)
:定义了程序的主方法,用于程序的入口点。
solution
方法内部实现:
int n = s.length();
boolean[] used = new boolean[n];
int cnt = 0;
int ans = 0;
int n = s.length();
:获取输入字符串s
的长度并存储在变量n
中。boolean[] used = new boolean[n];
:创建一个长度为n
的布尔型数组used
,用于标记字符串s
中字符是否已被使用。int cnt = 0;
:用于统计已使用的字符数量。int ans = 0;
:存储最终的结果,即满足条件的子串数量。
找到现有的 UCC 子串:
for (int i = 2; i < n; i++) {
if (s.substring(i - 2, i + 1).equals("UCC")) {
used[i] = used[i - 1] = used[i - 2] = true;
cnt += 3;
ans++;
}
}
- 这是一个
for
循环,从索引 2 开始遍历字符串s
直到索引n - 1
。 s.substring(i - 2, i + 1).equals("UCC")
:使用substring
方法提取从i - 2
到i
的子串(不包括i + 1
),并检查是否等于"UCC"
。- 如果等于
"UCC"
,将used
数组中相应位置的元素标记为true
,表示这三个字符已被使用,同时将cnt
加 3 并将ans
加 1。
找到未使用的 UC 或 CC 子串:
for (int i = 1; i < n; i++) {
if (!used[i] &&!used[i - 1] && m > 0) {
String t = s.substring(i - 1, i + 1);
if (t.equals("UC") || t.equals("CC")) {
used[i] = used[i - 1] = true;
cnt += 2;
ans++;
m--;
}
}
}
- 另一个
for
循环,从索引 1 开始遍历字符串s
直到索引n - 1
。 if (!used[i] &&!used[i - 1] && m > 0)
:检查当前字符和前一个字符是否未被使用,并且m
(编辑次数)大于 0。String t = s.substring(i - 1, i + 1);
:提取从i - 1
到i
的子串(不包括i + 1
)。- 如果子串等于
"UC"
或"CC"
,将相应位置的元素标记为true
,将cnt
加 2,ans
加 1,并将m
减 1。
处理剩下的单个字符:
ans += Math.min(m / 2, n - cnt);
m -= Math.min(m / 2, n - cnt) * 2;
ans += Math.min(m / 2, n - cnt);
:将ans
增加m / 2
和n - cnt
中的较小值,即将剩下的编辑次数尽可能平均分配给未使用的字符,每次处理两个字符。m -= Math.min(m / 2, n - cnt) * 2;
:更新m
的值,减去已经使用的编辑次数。
如果还有编辑次数大于 2,将其分成 3 个字符一组:
if (m > 2) {
ans += m / 3;
}
- 如果
m
大于 2,将m
除以 3 并将结果累加到ans
中,相当于添加UCC
字符串组。
main
方法内部实现:
System.out.println(solution(3, "UCUUCCCCC") == 3);
System.out.println(solution(6, "U") == 2);
System.out.println(solution(2, "UCCUUU") == 2);
- 调用
solution
方法并传入不同的参数,打印方法的返回结果是否等于给定的值,用于测试solution
方法的功能。
这段代码的主要目的是对输入的字符串 s
进行处理,根据给定的编辑次数 m
,找出并计算出满足特定条件(如 "UCC"
、"UC"
、"CC"
)的子串的最大数量。首先查找已有的 "UCC"
子串,然后使用剩余的编辑次数查找 "UC"
或 "CC"
子串,最后将剩余的编辑次数尽可能地用于生成新的子串。同时,使用 used
数组来标记字符是否已被使用,避免重复使用。