C++

 Computer >> コンピューター >  >> プログラミング >> C++
  1. C++で解く「すべての単語を連結した部分文字列」問題 ― ハッシュマップとスライディングウィンドウによる解法

    問題概要文字列 s と、すべて同じ長さの単語からなる配列 words が与えられます。このとき、s の中に存在する「words の各単語を、間に他の文字を挟まずにちょうど1回ずつ連結した部分文字列」の開始インデックスをすべて求めるのが目的です。たとえば、入力が barfoothefoobarman、words が [foo, bar] である場合、出力は [0, 9] になります。インデックス 0 から始まる部分文字列は barfoo、インデックス 9 から始まる部分文字列は foobar であり、どちらも foo と bar を1回ずつ連結したものに一致するためです。解法のアプローチこの問題

  2. C++で数独を解く!バックトラッキングによる数独ソルバーの実装方法

    9×9のマス目に並んだ数字のパズル「数独(Sudoku)」を、プログラムで自動的に解く方法を解説します。数独は9×9の数字グリッドから成り、その全体がさらに3×3のブロック(ボックス)に分割されているのが特徴です。数独を解くための基本ルール使用するのは1から9までの数字のみです。同じ行、同じ列、同じ3×3ブロック内に、同じ数字を重複させて配置することはできません。バックトラッキングによる解法ここでは「バックトラッキング」という手法を用いて数独を解きます。バックトラッキングとは、空いているセルに仮に数字を入れてみて、その配置が正しいかどうかを検証する方法です。もし配置が不正であれば別の数字を試し

  3. C++で区間を挿入する方法:重なる区間のマージアルゴリズムを解説

    問題概要互いに重ならない区間(インターバル)の集合が与えられます。この集合に対して新しい区間を挿入し、必要であれば重なる区間をマージ(統合)して結果を求めます。例えば、既存の区間が [[1,4],[6,9]] で、挿入する新しい区間が [2,5] の場合、出力は [[1,5],[6,9]] となります。新しい区間 [2,5] は既存の区間 [1,4] と重なっているため、両者が統合されて [1,5] になるからです。アルゴリズムの流れこの問題は、以下の手順で解くことができます。新しい区間を既存の区間リストの末尾に追加する区間の開始位置を基準にリスト全体をソートする(n は区間の総数)結果を格納

  4. C++でテキストの両端揃え(ジャスティフィケーション)を実装する方法

    単語の配列と最大幅 maxWidth が与えられたとき、各行がちょうど maxWidth 文字になるようにテキストを整形し、両端を揃える(フル・ジャスティファイ)ことを考えます。単語は貪欲法(グリーディーなアプローチ)で詰め込みます。つまり、1行にできるだけ多くの単語を収め、必要に応じて余分なスペース「 」を補って、各行の文字数をちょうど maxWidth に合わせます。単語間の余分なスペースは、できるだけ均等に分配します。行内のスペース数が単語間で均等に割り切れない場合は、左側の空きスロットに右側よりも多くのスペースを割り当てます。また、テキストの最終行は左揃えとし、単語間に余分な

  5. C++で編集距離(レーベンシュタイン距離)を求めるアルゴリズム

    問題の概要2つの単語 word1 と word2 が与えられたとき、word1 を word2 に変換するために必要な最小の操作回数を求める問題です。使用できる操作は次の3種類です。文字の挿入(insert)文字の削除(delete)文字の置換(replace)例えば、入力が "evaluate" と "fluctuate" の場合、必要な最小の操作回数は 5 になります。この問題は「編集距離(Edit Distance)」あるいは「レーベンシュタイン距離」と呼ばれる、動的計画法(DP)を用いて効率的に解ける有名な問題です。解法のアルゴリズム以下の手順に

  6. C++で最小ウィンドウ部分文字列を求める:スライディングウィンドウ法の解説

    問題概要 文字列SとTが与えられたとき、Sの中からTに含まれるすべての文字をカバーする最小のウィンドウ(部分文字列)を見つける問題です。例えば、S = ABHDAXCVBAGTXATYCB、T = ABC の場合、A・B・Cをすべて含む最短の部分文字列は CVBA となるため、これが答えになります。 解法のアプローチ:スライディングウィンドウ この問題は「スライディングウィンドウ(二つのポインタ)」という手法を使うことで、O(|S| + |T|) の時間計算量で効率的に解くことができます。rightポインタでウィンドウを広げ、条件を満たしたらleftポインタで縮める、という操作を繰り返すのが

  7. C++で2次元バイナリ行列から最大の長方形を求める方法(スタック活用)

    問題概要 0と1から構成される2次元のバイナリ行列が与えられます。この行列の中から「1」だけで構成される最大の長方形を見つけ、その面積を返すのが本記事のテーマです。 この問題を解くには、以下の手順に従います。 getAns関数(ヒストグラム内の最大長方形を求める) 配列aを受け取る関数getAnsを定義します。 スタックstを作成し、i := 0、ans := 0 と初期化します。 iがaのサイズ未満である間、以下を繰り返します。 スタックが空、または a[i] がスタックトップの値以上の場合:iをstに挿入し、iを1増やします。 それ以外の場合: height := a[スタックトップ

  8. C++での文字列インターリーブ判定:メモ化再帰による動的計画法の実装

    文字列インターリーブとは 3つの文字列 s1、s2、s3 が与えられたとき、s3 が s1 と s2 をインターリーブ(交互に織り交ぜる)することで形成できるかどうかを判定する問題です。 例えば、s1 = aabcc、s2 = dbbca、s3 = aadbbcbcac の場合、s3 は s1 と s2 の各文字を順序を保ちながら交互に組み合わせたものになっているため、結果は true になります。 解法のアプローチ この問題は、メモ化再帰(トップダウン方式の動的計画法)を用いることで効率的に解けます。i、j、k をそれぞれ s1、s2、s3 の現在位置とし、s3 の末尾から逆にたどりながら、

  9. C++で二分探索木(BST)を復元するアルゴリズムを解説

    問題の概要二分探索木(BST)において、誤って2つのノードの値が入れ替わってしまった状態を考えます。この記事では、入れ替わった2つのノードを特定し、木を正しい二分探索木の状態へ復元する方法をC++で解説します。例えば、次のような木が与えられた場合(左図)、復元後の木は右図のようになります。解決のアプローチ二分探索木には「中順(インオーダー)走査を行うと、ノードの値が昇順に並ぶ」という重要な性質があります。この性質を利用すると、入れ替わったノードを効率的に検出できます。具体的には、以下の手順で解決します。prev、first、second という3つのノード参照を用意します。findProble

  10. C++で異なる部分列の数を数える:動的計画法による解法

    問題の概要 2つの文字列 S と T が与えられたとき、S の部分列のうち T と一致するものが何通りあるかを数えるのがこの問題です。 ここでいう部分列(subsequence)とは、元の文字列から一部の文字(0個でも可)を取り除いて作られる新しい文字列のことであり、残った文字の相対的な順序は崩れません。たとえば「ACE」は「ABCDE」の部分列ですが、「AEC」は元の順序が保たれていないため部分列ではありません。 たとえば、入力が「baalllloonnn」と「balloon」の場合、T に一致する S の部分列は 36 通り存在します。 解法の考え方(動的計画法) この問題は動的計画法(

  11. C++での回文分割II – 最小カット数を動的計画法で求める方法

    問題概要文字列 s が与えられたとき、この文字列を複数の部分文字列に分割し、すべての部分が回文になるようにするために必要な最小のカット(切り分け)回数を求めてください。例えば、文字列が ababba の場合、[aba | bb | a] のように2箇所で切り分ければ各部分が回文になるため、答えは 2 回となります。アプローチ:動的計画法この問題は、文字列の後ろから順に「その位置以降を回文に分割するために必要な最小カット数」を配列に記録しながら計算することで、効率的に解くことができます。手順は以下の通りです。n := 文字列 s の文字数とするサイズ n + 1 の配列 res を作成するres

  12. C++で解くキャンディ分配問題:隣接する子供の評価値に基づく最小キャンディ数の求め方

    問題概要N人の子供が一列に並んでおり、それぞれの子供には評価値(rating)が割り当てられています。これらの子供たちにキャンディを配る際、以下の条件を満たす必要があります。すべての子供は最低1個のキャンディを受け取る必要があります。評価値が高い子供は、隣にいる子供よりも多くのキャンディを受け取る必要があります。このとき、配るべきキャンディの最小個数を求めます。例えば、入力が [1, 1, 3] の場合、出力は 4 となります。このとき、子供たちはそれぞれ 1個、1個、2個 のキャンディを受け取ることになります。解法のアプローチこの問題は、左から右、右から左の2回の走査(2パス方式)で効率的に

  13. C++で同一直線上に存在する最大点数を求めるアルゴリズム

    問題概要 2次元平面上に複数の点が与えられたとき、同じ直線上に存在する点の最大数を求めるのがこの問題の目的です。 例えば、下図のような6つの点が与えられた場合、最も多くの点が乗っている直線上には4つの点が存在します。 解法のアプローチ この問題は、隣り合う2点を通る直線を基準にして、残りのすべての点がその直線上に乗っているかどうかを順番に判定していくことで解けます。 3点 (x1, y1)、(x2, y2)、(x3, y3) が同一直線上にあるかどうかは、「傾きが等しい」こと、すなわち外積(クロス積)が0になることを利用して判定できます。 (y3 − y2) × (x2 − x1) = (

  14. C++で重複を含む回転ソート配列の最小値を見つける方法

    ソート済みの配列が、ある未知のピボット位置を基準に回転されているとします。このとき、配列の中から最小の要素を見つける必要があります。例えば、配列が [4,5,5,5,6,8,2,3,4] のような場合、最小要素は 2 となります。この問題は「回転ソート配列I」と似ていますが、配列に重複した値が含まれる点が異なります。重複があると単純な二分探索では判断が難しくなるため、条件分岐を工夫して探索範囲を狭めていく必要があります。アルゴリズムの考え方以下の手順で問題を解きます。search() というメソッドを定義する。引数は配列 arr、探索範囲の下限 low、上限 high。low == high

  15. C++で最大ギャップを求める方法|バケット法によるO(n)アルゴリズムの解説

    問題の概要 ソートされていない整数の配列が与えられます。この配列を昇順に並べ替えたときの、隣接する要素同士の差の最大値を求めてください。ただし、配列の要素数が2未満の場合は 0 を返します。 例として、配列が [12, 3, 9, 1, 17] の場合を考えてみましょう。ソートすると [1, 3, 9, 12, 17] となり、隣接要素間の差は「2, 6, 3, 5」になります。この中で最も大きいのは 3 と 9 の差である 6 なので、答えは 6 となります。 解法の考え方(バケット法) 実際に配列をソートしてから差を計算しても解けますが、その場合の計算量は O(n log n) です。こ

  16. C++で解くダンジョンゲーム:最小初期体力を求める動的計画法

    問題概要 悪魔たちが王女Pを捕らえ、ダンジョンの右下の部屋に閉じ込めてしまった――そんな物語を想像してみてください。ダンジョンはM行N列の格子状に並ぶ部屋で構成されており、勇敢な騎士Kは左上の部屋から出発し、戦いながら王女を救い出すために進まなければなりません。 騎士には正の整数で表される初期体力(HP)があります。移動中のどの時点でも体力が0以下に落ちれば、その瞬間に命を落としてしまいます。 一部の部屋には悪魔が待ち構えており、そこに入ると体力が減少します(負の整数として表現)。一方、空の部屋や魔法のオーブが置かれた部屋に入ると、体力は回復します(正の整数として表現)。 王女のもとへ一刻も早

  17. C++で解く「株式売買の最適タイミング IV」― 最大k回の取引で利益を最大化する方法

    問題概要 i番目の要素がi日目の株価を表す配列が与えられたとします。このとき、最大k回までの取引で得られる利益の最大値を求めるアルゴリズムを設計します。 例えば、入力が [3,2,6,4,0,3]、k = 2 の場合、出力は 7 になります。 その理由は次の通りです。 2日目(価格 = 2)に買い、3日目(価格 = 6)に売る → 利益は 6 − 2 = 4 5日目(価格 = 0)に買い、6日目(価格 = 3)に売る → 利益は 3 − 0 = 3 合計すると 4 + 3 = 7 となり、これが最大利益です。 解法のアプローチ この問題は、メモ化再帰(トップダウン型の動的計画法)を用い

  18. C++で最短の回文を求める方法|KMP法のLPS配列を活用した実装例

    問題概要 文字列 s が与えられます。この文字列の先頭に文字を追加していくことで、回文(前から読んでも後ろから読んでも同じになる文字列)に変換することができます。ここでの課題は、その操作によって作れる最短の回文を見つけることです。 たとえば、文字列が「abcc」の場合、答えは「ccbabcc」となります。 解き方のアプローチ この問題は、KMP法(文字列検索アルゴリズム)で使われる LPS配列(接尾辞とも一致する最長の接頭辞の長さを格納する配列)を応用すると、O(n) の計算量で効率よく解くことができます。 ポイントは次のとおりです。 元の文字列 s と、それを反転させた文字列を、区切り文

  19. C++で作る基本電卓:括弧と加減算を含む数式を計算する方法

    本記事では、C++を使って「開き括弧・閉じ括弧、プラス・マイナス記号、空白」を含む単純な数式を計算する、基本的な電卓の実装方法を解説します。 例えば、入力文字列が「5 + 2 - 3」であれば、計算結果は 4 になります。 アルゴリズム この問題は、スタックを活用することで効率的に解くことができます。具体的な手順は以下の通りです。 ret := 0、sign := 1、num := 0、n := 文字列 s の長さ として初期化します 整数型のスタック st を定義します i := 0 から始め、i < n の間、i を1ずつ増やしながら以下の処理を繰り返します x = s[i](i

  20. C++で0からnまでの整数に含まれる「1」の出現回数を効率的に数える方法

    問題概要 非負整数 n が与えられたとき、0 以上 n 以下のすべての整数に登場する数字「1」の合計出現回数を求める問題です。 たとえば入力が 15 の場合を考えてみましょう。「1」を含む数は [1, 10, 11, 12, 13, 14, 15] であり、これらに含まれる「1」は合計 8 個 です(11 には「1」が2個含まれる点に注意してください)。したがって出力は 8 となります。 解法のアプローチ すべての数を1つずつ調べる方法では計算量が膨大になるため、ここでは桁ごとに「1」の出現回数を数える効率的な手法を採用します。1の位・10の位・100の位…と各桁の位置について、その桁に「1

Total 5990 -コンピューター  FirstPage PreviousPage NextPage LastPage CurrentPage:175/300  20-コンピューター/Page Goto:1 169 170 171 172 173 174 175 176 177 178 179 180 181