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

C++で原点から最も遠い位置を求めるアルゴリズム

問題の概要

「L」「R」「?」のいずれかの文字で構成される文字列 s があるとします。「L」は左へ1単位移動すること、「R」は右へ1単位移動することを意味し、「?」は「L」または「R」のどちらにでも置き換え可能な文字です。初期位置が0であるとき、「?」を適切に置き換えることで、原点から到達できる最大距離を求めます。

例えば、入力が "LLRRL??" の場合、出力は 3 となります。「?」をすべて「L」に置き換えると、左へ5単位、右へ2単位移動することになり、最大変位は 5 − 2 = 3 だからです。

解法のアプローチ

この問題は、次の手順で効率的に解くことができます。

  • カウンタ op(「?」の個数)、l(「L」の個数)、r(「R」の個数)をそれぞれ0で初期化する

  • 文字列 s 内の各文字 it に対して以下を繰り返す:

    • it が 'L' と等しい場合 → l を1増やす

    • it が 'R' と等しい場合 → r を1増やす

    • それ以外の場合('?' の場合)→ op を1増やす

  • max(l, r) − min(l, r) + op を返す

この式が正しい理由はシンプルです。「?」はすべて同じ方向に割り当てられるため、左右の確定した移動量の差(絶対値)に「?」の総数を加えれば、理論上の最大距離が得られます。つまり、既存の「L」と「R」の差がどちら向きであっても、「?」をすべて有利な側に振ることで距離を最大化できます。

実装例

以下はC++による実装コードです。

#include <bits/stdc++.h>
using namespace std;
class Solution {
   public:
   int solve(string s) {
      int op = 0;
      int l = 0;
      int r = 0;
      for (auto &it : s) {
         if (it == 'L') {
            l++;
         } else if (it == 'R') {
            r++;
         } else {
            op++;
         }
      }
      return max(l, r) - min(l, r) + op;
   }
};
main() {
   Solution ob;
   cout << (ob.solve("LLRRL??"));
}

入力

"LLRRL??"

出力

3

計算量について

このアルゴリズムは文字列を一度だけ走査するため、時間計算量は O(n)、補助的な記憶領域は O(1) で済みます。非常にシンプルながら、あらゆる入力長に対して高速に動作するのが特徴です。

  1. 【C++】再帰を使って2次元マトリックスから2Dリンクリストを作成する方法

    行列(マトリックス)が与えられたとき、再帰的なアプローチを用いて、それを2Dリンクリストへ変換する方法を解説します。 ここで作成するリストの各ノードは、right(右方向)ポインタとdown(下方向)ポインタの2つのポインタを持ちます。rightポインタは同じ行の次の要素を、downポインタは同じ列の一つ下の行の要素を指します。 問題の概要 例えば、次のような3×3の行列が入力として与えられたとします。 102030405060708090 この場合、出力は次のようになります。各要素がノードとなり、横方向はrightポインタ、縦方向はdownポインタによって連結された、格子状のデータ構造が生成

  2. 【C++】先行順トラバーサルの文字列から二分木を復元するアルゴリズムと実装

    問題概要 二分木が与えられ、その根ノードに対して先行順(プレオーダー)の深さ優先探索を実行することを考えます。 この走査では、各ノードを訪問するたびに、まずそのノードの深さDと同じ数だけダッシュ「-」を出力し、その直後にノードの値を表示します。深さがDのノードの直接の子の深さはD+1となり、根ノードの深さは0です。 さらに重要なルールとして、あるノードに子が1つしか存在しない場合、その子は必ず左の子であることが保証されています。この走査の出力文字列Sが与えられたとき、元の二分木を復元し、その根を返すのが本問題です。 例えば、入力が「1-2--3--4-5--6--7」の場合、復元される木は次