1.概要

このチュートリアルでは、文字列から繰り返し文字を削除するためのJavaの手法について説明します。

それぞれの手法について、時間と空間の複雑さについても簡単に説明します。

2.

distinct

を使う

Java 8で導入された

distinct

メソッドを使用して、文字列から重複した文字列を削除することから始めましょう。

以下のコードでは、与えられた文字列オブジェクトから

IntStream

のインスタンスを取得しています。次に、重複を削除するために

distinct

メソッドを使用しています。次に、

forEach

を使用して異なる文字をループし、それらを

StringBuilder

に追加します。

StringBuilder sb = new StringBuilder();
str.chars().distinct().forEach(c -> sb.append((char) c));


  • 時間の複雑さ:

    **


    _ O(n)

    _

    – ループの実行時間は入力文字列のサイズに正比例します

  • 補助スペース:**

    O(n)



    __distinct


    は、順序を維持するために中間の

    LinkedHashSet__を作成します。

  • 順序を維持します:** はい

そして、Java 8がこのタスクを非常にうまく解決してくれることは素晴らしいことですが、それを私たち自身のロールアップの努力と比較してみましょう。

3.

indexOf

を使う

文字列から重複を削除する単純な方法は、単に入力をループ処理し、メソッド

__indexOf

__を使用して、結果の文字列にその文字がすでに存在するかどうかを調べるだけです。

StringBuilder sb = new StringBuilder();
int idx;
for (int i = 0; i < str.length(); i++) {
    char c = str.charAt(i);
    idx = str.indexOf(c, i + 1);
    if (idx == -1) {
        sb.append(c);
    }
}


  • 時間の複雑さ:




    _ O(n



    n)_ – ループの実行時間は入力データセットのサイズの2乗に正比例

  • 補助スペース:**

    O(1)

    – ループ内にインデックスと文字の値を格納するには一定のスペースが必要です

  • 順序を維持します:** はい

これには補助スペースがないという利点がありますが、Core Javaのアプローチよりもはるかに遅くなります。

4.文字配列を使う

  • それを

    char

    配列に変換してから各文字をループ処理し、それを後続のすべての文字と比較することで、文字列から重複を削除することもできます。

以下に示すように、forループを2つ作成し、各要素が文字列内で繰り返されているかどうかを確認しています。重複が見つかった場合は

repeatedCtr

をインクリメントして

StringBuilder

に追加しないようにします。

char[]chars = str.toCharArray();
StringBuilder sb = new StringBuilder();
boolean repeatedChar;
for (int i = 0; i < chars.length; i++) {
    repeatedChar = false;
    for (int j = i + 1; j < chars.length; j++) {
        if (chars[i]== chars[j]) {
            repeatedChar = true;
            break;
        }
    }
    if (!repeatedChar) {
        sb.append(chars[i]);
    }
}


  • 時間の複雑さ:



    __ O(n


    n)

    – 内側と外側のループは両方とも


    n

    __反復が必要

  • 補助スペース:**

    O(1)

    – 入力文字列の繰り返し文字数に依存する

    __repeatedCtr

    __を格納するために一定のスペースが必要

  • 順序を維持します:** いいえ

繰り返しになりますが、2回目の試行はCore Java製品と比べてパフォーマンスが劣りますが、次の試行でどこに到達するかを見てみましょう。

5.ソートを使う

あるいは、入力文字列をグループの重複にソートすることで、繰り返し文字を排除することができます。 ** そのためには、文字列を

__char a


rrayに変換し、

Arrays

静的メソッド

sort.

を使用してソートする必要があります。最後に、ソートされた

char__配列を反復処理します。

繰り返しのたびに、配列の各要素を前の要素と比較します。要素が異なる場合は、現在の文字を__StringBuilderに追加します。

StringBuilder sb = new StringBuilder();
if(!str.isEmpty()) {
    char[]chars = str.toCharArray();
    Arrays.sort(chars);

    sb.append(chars[0]);
    for (int i = 1; i < chars.length; i++) {
        if (chars[i]!= chars[i - 1]) {
            sb.append(chars[i]);
        }
    }
}


  • 時間の複雑さ:

    **

    __ O(n log n)


    – 配列の比較ソートは最悪の場合、時間の複雑さは

    O(n log n)__になります。

  • 補助スペース:**

    O(n)



    sort



    O(n)

    補助スペースを使用するQuicksortを使用し、

    __ toCharArrayは

    __Stringのコピーを作成

  • 順序を維持します:** いいえ

だから、私たちは時空間のトレードオフを見始めています。ここでは、パフォーマンスを向上させるためにスペースを交換しました。もう一度試してみましょう。

6.

Set

を使う

文字列から繰り返し文字を削除するもう1つの方法は、

Set

を使用することです。出力文字列の文字の順序を気にしないのであれば、

HashSet

を使用できます。それ以外の場合は、挿入順序を維持するために

__LinkedHashSet

__を使用できます。

どちらの場合も、入力文字列をループ処理して各文字を

Set

に追加します。文字がセットに挿入されたら、それを繰り返して

__StringBuilder

__に追加し、結果の文字列を返します。

StringBuilder sb = new StringBuilder();
Set<Character> linkedHashSet = new LinkedHashSet<>();

for (int i = 0; i < str.length(); i++) {
    linkedHashSet.add(str.charAt(i));
}

for (Character c : linkedHashSet) {
    sb.append(c);
}


  • 時間の複雑さ:

    **


    _ O(n)

    _

    – ループの実行時間は入力文字列のサイズに正比例します

  • 補助スペース:**

    O(n)



    Set

    に必要なスペースは入力ストリングのサイズによって異なります

  • 順序を維持します。**


    _LinkedHashSet –


    はい、

    HashSet _

    –いいえ

そして今、私たちはコアJavaアプローチにマッチしました!これを見つけることは、それが既に明らかにされていることと非常によく似ていることを知ることはそれほどショックではありません。

7.まとめ

  • この記事では、Javaで文字列から繰り返し文字を削除するいくつかの方法について説明しました** これらのメソッドの時間と空間の複雑さも調べました。

いつものように、コードスニペットはhttps://github.com/eugenp/tutorials/tree/master/java-strings[over on GitHub]にあります。