题目解析:小C的字符串| 豆包MarsCode AI刷题

114 阅读6分钟

小C的字符串

问题描述

小M拥有一个由字母 'a' 和 'b' 组成的字符串。她可以进行以下两种操作:

  1. 找到下标 ii,满足 ai=′b′ai​=′b′ 且 ai+1=′a′ai+1​=′a′,并交换这两个字符。
  2. 找到下标 ii,满足 ai=′a′ai​=′a′ 且 ai+1=′b′ai+1​=′b′,并删除这两个字符。

其中,操作 2 可以进行无限次,而操作 1 只能执行 kk 次。请帮助小M通过这两种操作,尽量减少字符串的长度,并输出最终得到的最小字符串。如果所有字符都可以被删除,输出 -1

例如:给定字符串 "ababbaa" 和 k=1k=1,通过一次交换和多次删除后,最终得到的字符串为 "a"

测试样例

样例1:

输入:n = 7 ,k = 1 ,a = "ababbaa"
输出:'a'

样例2:

输入:n = 5 ,k = 0 ,a = "aabaa"
输出:'aaa'

样例3:

输入:n = 6 ,k = 2 ,a = "bbabba"
输出:'bb'

数据结构选择

  • 使用 StringBuffer 来处理字符串的修改操作,因为它支持高效的插入和删除操作。

思路分析

  1. 优先删除操作

    • 由于操作2可以无限次执行,因此我们应该优先考虑删除 'a' 和 'b' 相邻的组合。这样可以最大限度地减少字符串的长度。
  2. 交换操作

    • 如果操作2无法继续执行(即没有 'a' 和 'b' 相邻的组合),我们可以考虑使用操作1来创造新的 'a' 和 'b' 相邻的组合,以便继续执行删除操作。
    • 注意,操作1只能执行 k 次,因此我们需要谨慎使用。
  3. 循环处理

    • 我们可以使用一个循环来不断执行删除操作,直到没有 'a' 和 'b' 相邻的组合为止。
    • 在每次循环中,检查是否可以执行交换操作来创造新的删除机会。
  4. 边界情况

    • 如果字符串长度为0,说明所有字符都被删除了,返回 -1
    • 如果字符串长度不为0,返回最终的字符串。

具体思路

  1. 初始字符串处理

    • 创建一个 StringBuffer 对象 sBuffer,将输入字符串 a 复制到其中,以便进行后续的字符删除操作。
    • 使用一个循环遍历 sBuffer,条件是当前索引 i 小于 sBuffer 的长度减 1。在这个循环中,如果发现当前字符为 'a' 且下一个字符为 'b',就删除这两个字符(通过 sBuffer.delete(i, i + 2)),然后将索引 i 减 1,以确保在删除字符后能够正确地继续检查新的字符组合。如果 i 变为 -1,则将其重置为 0。如果 i 为 0 且 sBuffer 的长度小于等于 1,则跳出循环。如果没有发现 'a' 和 'b' 的组合,则将索引 i 加 1。
  2. 重复操作

    • 接下来进行 k 次循环操作。在每次循环中,设置一个标志变量 flag 初始值为 1。然后再次遍历 sBuffer,条件是当前索引 j 小于 sBuffer 的长度减 1。在这个循环中,如果发现当前字符为 'b' 且下一个字符为 'a',就删除这两个字符,并像之前一样处理索引 j。如果在这个过程中 j 变为 -1,则将其重置为 0。如果 j 为 0 且 sBuffer 的长度小于等于 1,则将 flag 设为 0 并跳出循环。如果没有发现 'b' 和 'a' 的组合,则将索引 j 加 1。如果 flag 为 0,表示在这次循环中没有成功完成操作,就跳出外层循环。
  3. 最终处理和返回结果

    • 最后,再次进行与初始字符串处理类似的操作,检查并删除 'a' 和 'b' 的组合。
    • 如果 sBuffer 的长度为 0,说明经过一系列操作后字符串被完全删除,此时返回“-1”;否则,返回 sBuffer 转换为字符串后的结果。

代码实现


public class Main {
    public static String solution(int n, int k, String a) {
        // write code here
        StringBuffer sBuffer = new StringBuffer(a);
        for(int i = 0; i < sBuffer.length() - 1; ){
            if(sBuffer.charAt(i) == 'a' && sBuffer.charAt(i + 1) == 'b'){
                sBuffer.delete(i, i + 2);
                i--;
                if(i == -1){
                    i = 0;
                }
                if(i == 0 && sBuffer.length() <= 1){
                    break;
                }
            }else{
                i++;
            }
        }

        for(int i = 0; i < k; i++){
            int flag = 1;
            for(int j = 0; j < sBuffer.length() - 1; ){
                if(sBuffer.charAt(j) == 'b' && sBuffer.charAt(j + 1) == 'a'){
                    sBuffer.delete(j, j + 2);
                    j--;
                    if(j == -1){
                        j = 0;
                    }
                    if(j == 0 && sBuffer.length() <= 1){
                        flag = 0;
                        break;
                    }
                }else{
                    j++;
                }
            }
            if(flag == 0){
                break;
            }
        }

        for(int i = 0; i < sBuffer.length() - 1; ){
            if(sBuffer.charAt(i) == 'a' && sBuffer.charAt(i + 1) == 'b'){
                sBuffer.delete(i, i + 2);
                i--;
                if(i == -1){
                    i = 0;
                }
                if(i == 0 && sBuffer.length() <= 1){
                    break;
                }
            }else{
                i++;
            }
        }

        if(sBuffer.length() == 0){
            return "-1";
        }
        return sBuffer.toString(); // placeholder return
    }

    public static void main(String[] args) {
        System.out.println(solution(7, 1, "ababbaa").equals("a"));
        System.out.println(solution(5, 0, "aabaa").equals("aaa"));
        System.out.println(solution(6, 2, "bbabba").equals("bb"));
    }
}

关于字符串处理

一、字符串处理技巧

  1. 使用StringBufferStringBuilder:当需要对字符串进行频繁的修改操作时,如这段代码中的多次删除操作,使用StringBufferStringBuilder比使用不可变的String类更高效。StringBufferStringBuilder提供一系列方法来方便地进行字符串的修改,而不会产生大量的中间字符串对象。
  2. 遍历和索引控制:在遍历字符串时,要注意正确控制索引。这段代码中通过仔细地处理索引的增减,确保在删除字符后能够正确地继续遍历字符串,避免遗漏或重复处理字符。特别是在删除操作后,需要根据具体情况调整索引,以保证后续的遍历能够覆盖所有的字符。

二、循环和条件判断的运用

  1. 多重循环的结构:代码中使用多重循环来重复执行特定的操作。在设计多重循环时,要确保每个循环的目的清晰,并且循环条件合理。同时,要注意循环之间的关系,避免不必要的重复或遗漏。
  2. 条件判断的准确性:通过精确的条件判断来确定何时执行特定的操作。例如,在这段代码中,根据字符的组合情况进行判断,决定是否删除字符。条件判断应该尽可能准确地反映问题的逻辑,以确保程序的正确性。

三、错误处理和边界情况考虑

  1. 边界情况:代码中考虑一些边界情况,如字符串长度为 0 或 1 时的处理,以及索引变为 -1 时的重置。在编程中,要充分考虑各种边界情况,以确保程序在各种情况下都能正确运行。
  2. 错误处理:当出现特定情况(如字符串被完全删除)时,代码返回特定的标识“-1”。这是一种简单的错误处理方式,可以让调用者知道出现了异常情况。在实际编程中,应该根据具体需求设计更详细的错误处理机制,以便更好地处理各种错误情况。