一、题目
构造有效字符串的最少插入数
二、代码
做出来咯🎉🎉🎉
// 1
class Solution {
public int addMinimum(String word) {
// 将字符串转换为字符数组
// 从前往后对每个字符进行判断-判断是否有效
// 将字符分为a,b,c三种情况去处理
int count = 0;
char c[] = word.toCharArray();
for(int i=0;i<c.length;i++) {
// 对每个字符进行处理:分三种情况
if(c[i]=='a') {
if(c[i+1]=='b') {
if(c[i+2]=='c') {
i = i+2;
}else {
count++;
i++;
}
}
}else if(c[i]=='b') {
if(c[i+1]=='c') {
count++;
i++;
}else {
count = count+2;
}
}else if(c[i]=='c') {
count = count+2;
}
}
return count;
}
}
/**
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
at line 11, Solution.addMinimum
at line 54, __DriverSolution__.__helper__
at line 84, __Driver__.main
*/
Kim:从前向后判断字符会出现数组越界问题;于是尝试从后向前遍历字符-但仍会因--操作对在数组下标1附近进行判断时会出现越界情况,因此对处理进行筛选,下标小于c.length-2时进行处理,剩余部分做特殊处理
// 2
class Solution {
public static int addMinimum(String word) {
// 将字符串转换为字符数组
// 从前往后对每个字符进行判断-判断是否有效
// 将字符分为a,b,c三种情况去处理
int count = 0;
char c[] = word.toCharArray();
// 标记是否在第一步处理中对最后两个元素已处理完
boolean f1 = false;
boolean f2 = false;
for(int i=0;i<c.length-2;i++) {
// 对小标小于c.length-2的字符进行处理:分三种情况
if(c[i]=='a') {
if(c[i+1]=='b') {
if(c[i+2]=='c') {
// 由于在处理过程中会随时改变i的值,故判断语句应放在最前
if(i==c.length-3) {
f1 = true;
}
i = i+2;
}else {
if(i==c.length-3) {
f2 = true;
}
count++;
// System.out.println("a"+count);
i++;
}
}else if(c[i+1]=='c') {
if(i==c.length-3) {
f2 = true;
}
count++;
// System.out.println("b"+count);
i++;
}else {
count = count+2;
// System.out.println("c"+count);
}
}else if(c[i]=='b') {
if(c[i+1]=='c') {
if(i==c.length-3) {
f2 = true;
}
count++;
// System.out.println("d"+count);
i++;
}else {
count = count+2;
// System.out.println("e"+count);
}
}else {
count = count+2;
// System.out.println("f"+count);
}
}
// 对剩余的最后两个字符进行处理
int l2 = (c.length)-2;
int l1 = (c.length)-1;
// System.out.println(f2);
// System.out.println(f1);
if(f2==true && f1==true) {
return count;
}else if(f2==true) {
count = count+2;
// System.out.println("g"+count);
}else {
if(c[l2]=='a') {
if(c[l1]=='a') {
count = count+4;
// System.out.println("h"+count);
}else {
count++;
// System.out.println("i"+count);
}
}else if(c[l2]=='b') {
if(c[l1]=='c') {
count++;
// System.out.println("j"+count);
}else {
count = count+4;
// System.out.println("k"+count);
}
}else {
count = count+4;
// System.out.println("l"+count);
}
}
return count;
}
}
/**
java.lang.ArrayIndexOutOfBoundsException: Index -1 out of bounds for length 1
at line 71, Solution.addMinimum
at line 54, __DriverSolution__.__helper__
at line 84, __Driver__.main
*/
Kim:在IDEA中执行自己随意设置的两个个测试用例都没有问题,但在官网运行行总会出现数组越界问题,可恶!ʕ◉ᴥ◉ʔ
Kim:最后发现是少了字符长度为1和2的两种情况才会越界呜呜呜~
Kim:调试过程中还修改了 判断 在第一步处理中对最后两个元素是否已处理完 的逻辑 (第六个测试用例发现)
测试用例:
1."b"
2."aaa"
3."abc"
4."abcaacb"
5."abcaacbcb"
6."aaabca"
// 3
class Solution {
public static int addMinimum(String word) {
// 将字符串转换为字符数组
// 从前往后对每个字符进行判断-判断是否有效
// 将字符分为a,b,c三种情况去处理
int count = 0;
char c[] = word.toCharArray();
// 标记是否在第一步处理中对最后两个元素已处理完
boolean f1 = false;
boolean f2 = false;
if(c.length==1) {
return 2;
} else if(c.length>2) {
for(int i=0;i<c.length-2;i++) {
// 对小标小于c.length-2的字符进行处理:分三种情况
if(c[i]=='a') {
if(c[i+1]=='b') {
if(c[i+2]=='c') {
i = i+2;
if(i==c.length-2) {
f2 = true;
}
if(i==c.length-1) {
f1 = true;
}
}else {
count++;
// System.out.println("a"+count);
i++;
if(i==c.length-2) {
f2 = true;
}
if(i==c.length-1) {
f1 = true;
}
}
}else if(c[i+1]=='c') {
count++;
// System.out.println("b"+count);
i++;
if(i==c.length-2) {
f2 = true;
}
if(i==c.length-1) {
f1 = true;
}
}else {
count = count+2;
// System.out.println("c"+count);
}
}else if(c[i]=='b') {
if(c[i+1]=='c') {
count++;
// System.out.println("d"+count);
i++;
if(i==c.length-2) {
f2 = true;
}
if(i==c.length-1) {
f1 = true;
}
}else {
count = count+2;
// System.out.println("e"+count);
}
}else {
count = count+2;
// System.out.println("f"+count);
}
}
}
// 对剩余的最后两个字符进行处理
int l2 = (c.length)-2;
int l1 = (c.length)-1;
// System.out.println(f2);
// System.out.println(f1);
if(f1==true) {
return count;
}else if(f2==true) {
count = count+2;
// System.out.println("g"+count);
}else {
if(c[l2]=='a') {
if(c[l1]=='a') {
count = count+4;
// System.out.println("h"+count);
}else {
count++;
// System.out.println("i"+count);
}
}else if(c[l2]=='b') {
if(c[l1]=='c') {
count++;
// System.out.println("j"+count);
}else {
count = count+4;
// System.out.println("k"+count);
}
}else {
count = count+4;
// System.out.println("l"+count);
}
}
return count;
}
}
Kim:最终修改正确后的代码
三、题解
考虑相邻字母
对于两个相邻字符 x 和 y(x 在 y 左侧),使 s (word记为s)有效的话需要插入 y−x−1(abc顺序计算正好各差一位,故若是正确顺序则应为后减前再-1为0,此时不用添加任何字母) 个字母(这里计算的每次都是以当前 i 为下标的字母前需要插入几个字母)。
考虑到这可能是个负数(如:cb,b比c小但在b后,就会出现b-c=-1的情况),可以通过如下技巧转换在[0,2] 内:(y−x−1+3) mod 3 (每两组串联的"abc"之间任意两个字母最多相差2;意思是从相邻两组的每一组中分别任意取出一个字母,这两个字母最大相差2,故对3取模)
例如 x=‘a’,y=‘c’,则有 (‘c’−‘a’+2) mod 3=1,意思是需要补一个字母 ‘b’。
例如 x=‘c’,y=‘a’,则有 (‘a’−‘c’+2) mod 3=0,无需补字母。
最后补齐开头的 s[0]−‘a’(由于代码中使用了 i-1 为了防止数组越界,故从下标为1的开始遍历,又由于word首字母一定为a,故只需要计算当前字母与a的差值即可,当前字母一定大于等于a,即需要补上一次判断首字母前需要插入几个字母),和结尾的 ‘c’−s[n−1](**与补齐开头类似,这里需要补上一次判断尾字母后需要插入几个字母【尾字母一定为c,即当前字母一定小于等于c】)。这俩可以合并为s[0]−s[n−1]+2。
/**
题解给出了两种思路,一个为考虑相邻字母另一个为abc的周期数,我选择第一种与自己思路相近的答案进行学习解析
*/
class Solution {
public int addMinimum(String word) {
var s = word.toCharArray();
int ans = s[0] + 2 - s[s.length - 1];
for (int i = 1; i < s.length; ++i)
ans += (s[i] + 2 - s[i - 1]) % 3;
// (s[i] - s[i-1] - 1 + 3)%3
return ans;
}
}
作者:力扣官方题解
来源:力扣(LeetCode)
四、总结
其他:
java中使用s.toCharArray()将字符串转换成字符数组