文字列操作の高度なテクニック:StringBuilder APIと回転アルゴリズム

StringBuilder APIの基本操作

主要なStringBuilderメソッド

  1. append(String str):文字列を末尾に追加します。
  2. insert(int offset, String str):指定位置に文字列を挿入します。
  3. delete(int start, int end):指定範囲の文字を削除します。
  4. deleteCharAt(int index):指定位置の文字を削除します。
  5. reverse():文字列を反転します。
  6. toString():StringBuilderをStringに変換します。
  7. setCharAt(int index, char ch):指定位置の文字を設定します。
  8. charAt(int index):指定位置の文字を取得します。
  9. length():文字列の長さを返します。
  10. substring(int start, int end):指定範囲の部分文字列を返します。

サンプルコード

public class StringManipulator {
    public static void main(String[] args) {
        // StringBuilderインスタンスの作成
        StringBuilder builder = new StringBuilder("こんにちは");

        // append()メソッド:末尾に文字列を追加
        builder.append(" 世界");
        System.out.println("追加後: " + builder.toString()); // 出力: "こんにちは 世界"

        // insert()メソッド:指定位置に文字列を挿入
        builder.insert(5, " Java");
        System.out.println("挿入後: " + builder.toString()); // 出力: "こんにちは Java 世界"

        // delete()メソッド:指定範囲の文字を削除
        builder.delete(5, 10);
        System.out.println("削除後: " + builder.toString()); // 出力: "こんにちは 世界"

        // deleteCharAt()メソッド:指定位置の文字を削除
        builder.deleteCharAt(5);
        System.out.println("文字削除後: " + builder.toString()); // 出力: "こんにちは世界"

        // reverse()メソッド:文字列を反転
        builder.reverse();
        System.out.println("反転後: " + builder.toString()); // 出力: "界世 はちにんこ"

        // toString()メソッド:StringBuilderをStringに変換
        String result = builder.toString();
        System.out.println("String変換: " + result); // 出力: "界世 はちにんこ"

        // setCharAt()メソッド:指定位置の文字を設定
        builder.setCharAt(0, '界');
        System.out.println("文字設定後: " + builder.toString()); // 出力: "界世 はちにんこ"

        // charAt()メソッド:指定位置の文字を取得
        char character = builder.charAt(1);
        System.out.println("インデックス1の文字: " + character); // 出力: "世"

        // length()メソッド:文字列の長さを取得
        int size = builder.length();
        System.out.println("長さ: " + size); // 出力: 10

        // substring()メソッド:部分文字列を取得
        String portion = builder.substring(0, 5);
        System.out.println("部分文字列 (0, 5): " + portion); // 出力: "界世 は"
    }
}

各メソッドの説明

  1. append(String str)
  • 文字列strをStringBuilderの末尾に追加します。
builder.append(" 世界"); // "こんにちは 世界"
  1. insert(int offset, String str)
  • 指定位置offsetに文字列strを挿入します。
builder.insert(5, " Java"); // "こんにちは Java 世界"
  1. delete(int start, int end)
  • startからendまでの文字を削除します。
builder.delete(5, 10); // "こんにちは 世界"
  1. deleteCharAt(int index)
  • 指定位置indexの文字を削除します。
builder.deleteCharAt(5); // "こんにちは世界"
  1. reverse()
  • 文字列を反転します。
builder.reverse(); // "界世 はちにんこ"
  1. toString()
  • StringBuilderをStringに変換します。
String result = builder.toString(); // "界世 はちにんこ"
  1. setCharAt(int index, char ch)
  • 指定位置indexの文字をchに設定します。
builder.setCharAt(0, '界'); // "界世 はちにんこ"
  1. charAt(int index)
  • 指定位置indexの文字を取得します。
char character = builder.charAt(1); // '世'
  1. length()
  • 文字列の長さを取得します。
int size = builder.length(); // 10
  1. substring(int start, int end)
  • startからendまでの部分文字列を取得します。
String portion = builder.substring(0, 5); // "界世 は"

問題解決

問題分析

最初はJavaの組み込みメソッドを使用していましたが、実行時間とメモリ使用量が最適ではなかったため、より効率的なアプローチを学び直しました。

主な戦略:

  • 前後の空白と余分な空白を削除
  • 全体の文字列を反転
  • 個々の単語を反転(上記の関数を再利用)

最適化前:

最適化後:

ループによる回転操作は後ろから前へ進むのが最適で、そうしないとエラーが発生する可能性があります。

コード実装

問題151:単語の反転
class Solution {
    public String reverseWords(String input) {
        StringBuilder processed = cleanString(input);
        reverseFull(processed, 0, processed.length() - 1);
        reverseEachWord(processed);
        return processed.toString();
    }

    // 前後の空白と余分な空白を削除
    private StringBuilder cleanString(String text) {
        int begin = 0;
        int finish = text.length() - 1;
        
        // 前後の空白を削除
        while(text.charAt(begin) == ' ') begin++;       
        while(text.charAt(finish) == ' ') finish--;

        StringBuilder builder = new StringBuilder();
        while(begin <= finish){
            char c = text.charAt(begin);
            // 余分な空白を削除
            // 1. 文字自体が空白
            // 2. 文字が空白で、前の文字が空白でない
            if(c != ' ' || builder.charAt(builder.length() - 1) != ' '){
                builder.append(c);
            }
            begin++;
        }       
        return builder;
    }

    // 全体の文字列を反転
    private void reverseFull(StringBuilder builder, int start, int end){
        while(start < end){
            char temp = builder.charAt(start);
            builder.setCharAt(start, builder.charAt(end));
            builder.setCharAt(end, temp);
            start++; end--;
        }
    }

    // 各単語を反転
    private void reverseEachWord(StringBuilder builder){
        int start = 0;
        int end = 1;
        int n = builder.length(); 
        while(start < n){
            while(end < n && builder.charAt(end) != ' '){
                end++;
            }

            reverseFull(builder, start, end - 1);
            start = end + 1;
            end = start + 1;
        }
    }
}
問題55:文字列の回転
import java.util.*;

public class StringRotator {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 整数nを読み込む
        int rotations = scanner.nextInt();
        scanner.nextLine(); // 改行文字を消費
        
        // 文字列を読み込みStringBuilderを作成
        StringBuilder text = new StringBuilder(scanner.nextLine());
        
        // 回転回数を文字列長で割った余りを計算
        rotations = rotations % text.length();
        
        // 文字列を回転
        while (rotations > 0) {
            char lastChar = text.charAt(text.length() - 1);
            for (int i = text.length() - 1; i > 0; i--) {
                text.setCharAt(i, text.charAt(i - 1));
            }
            text.setCharAt(0, lastChar);
            rotations--;
        }

        // 結果を出力
        System.out.println(text.toString());
    }
}

タグ: Java stringbuilder 文字列操作 アルゴリズム LeetCode

5月27日 02:03 投稿