C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で文字列を圧縮する方法:連続する重複文字を1つにまとめる

はじめに

文字列 s が与えられたとき、連続して重複している文字を取り除き、各文字を1つだけ残した新しい文字列を返すことを考えます。同じ文字が続けて現れる場合は、それらを1文字にまとめます。文字の出現順序は元のまま維持されます。

例として、入力が "heeeeelllllllloooooo" の場合、出力は "helo" になります。

解法のアプローチ

この問題は、以下の手順で解くことができます。

  • 結果を格納するための空の文字列 ret を用意します。
  • i = 0 から s のサイズ未満まで、i を1ずつ増やしながらループします。
  • ret が空でなく、ret の最後の文字が s[i] と同じである場合は、その文字をスキップして次の反復へ進みます。
  • それ以外の場合は、s[i] を ret の末尾に連結します。
  • ループ終了後、ret を返します。

C++での実装例

#include <bits/stdc++.h>
using namespace std;
class Solution {
  public:
  string solve(string s) {
    string ret = "";
    for(int i = 0; i < s.size(); i++){
      if(ret.size() && ret.back() == s[i]){
        continue;
      }
      ret += s[i];
    }
    return ret;
  }
};
int main(){
  Solution ob;
  cout << (ob.solve("heeeeelllllllloooooo"));
}

入力

"heeeeelllllllloooooo"

出力

helo

コードの解説

このアルゴリズムのポイントは、std::string::back() メソッドを使って、結果文字列の末尾の文字と現在処理中の文字を比較する点です。両者が一致する場合は continue によってその文字をスキップし、一致しない場合のみ文字を追加します。これにより、連続する重複文字が自然に1文字へと圧縮されます。

計算量について見てみましょう。入力文字列を一度だけ走査するため、時間計算量は O(n) です。また、結果を格納する文字列が必要となるため、空間計算量も O(n) となります(n は入力文字列の長さ)。

なお、C++20以降では std::ranges::uniquestd::unique を活用することでも同様の処理を実現できますが、この手動実装のアプローチはロジックが明快で、学習目的にも非常に適しています。

  1. C++で解く「ジャンプゲームV」:メモ化再帰による最大訪問インデックス数の求め方

    問題の概要整数型の配列 arr と整数 d が与えられます。1ステップごとに、インデックス i から次の場所へジャンプできます。右方向: i + x(ただし i + x < n、かつ x は 1 以上 d 以下)左方向: i - x(ただし i - x >= 0、かつ x は 1 以上 d 以下)ここで n は配列のサイズです。さらに重要な制約として、インデックス i から j へジャンプできるのは、arr[i] > arr[j] であり、かつ i と j の間にあるすべてのインデックス k に対して arr[i] > arr[k] を満たす場合のみです。つまり、より低

  2. C++で文字列をトークン化(分割)する2つの方法を解説

    文字列のトークン化(分割)とは、1つの文字列を区切り文字(スペースやカンマなど)を基準に、複数の部分文字列へ分割する処理のことです。C++では、標準ライブラリだけでもいくつかの方法で実現できます。本記事では、代表的な2つの方法をサンプルコード付きで紹介します。方法1:stringstreamを使って空白で分割する1つ目の方法は、stringstreamを使ってスペースで区切られた単語を順に読み取る方法です。この方法はやや制限がありますが、適切なチェックを加えれば十分に目的を果たすことができます。サンプルコード#include <vector> #include <string