-
C++で配列内のkで割り切れる要素の個数を数える方法
本記事では、正の整数からなる配列と整数変数 k が与えられたとき、配列の中に k で割り切れる要素がいくつあるかを求める方法を解説します。入力例と出力例入力 − int arr[] = {4, 2, 6, 1, 3, 8, 10, 9}, k = 2出力 − 2 で割り切れる要素の個数は − 5説明 − 配列の各要素を k で割り、余りが 0 になるかどうかを確認します。4、2、6、8、10 は 2 で割り切れますが、1、3、9 は割り切れません。したがって、k(= 2)で完全に割り切れる要素は 5 個となります。入力 − int arr[] = {3, 2, 9, 15, 0, 8, 10}
-
C++で文字列内の母音ペアを数える方法を解説
はじめに 文字列が与えられ、その中に「隣り合う2文字がどちらも母音であるペア」がいくつ含まれるかを数えるのが今回の課題です。英語のアルファベットには a、i、e、o、u の5つの母音があり、それ以外の文字は子音と呼ばれます。 入力例と出力例 入力: string str = tutorials point 出力: 与えられた文字列内の母音ペアの数:2 説明: 与えられた文字列から作れる隣接ペアは (t, u)、(u, t)、(t, o)、(o, r)、(r, i)、(i, a)、(a, l)、(l, s)、(s, p)、(p, o)、(o, i)、(i, n)、(n, t) です。このうち、
-
C++で二分木を単一リンクリストに変換するプログラム
二分木が与えられたとき、それをその場(in-place)で単一リンクリストに変換することを考えます。ここでの「その場」とは、追加のノードを生成せず、既存のノードのポインタを付け替えるだけで変換を行うことを意味します。例えば、次のような二分木が入力として与えられた場合:出力は以下のように、すべてのノードが右側のポインタだけで連結されたリンクリストになります:解法のアプローチこの問題を解くために、以下の手順に従います。ポインタ prev を null で初期化します。これは「直前に処理したノード」を保持するためのものです。ルートを引数にとる再帰関数 solve() を定義します。ルートが null
-
C++で爆弾1つで倒せる最大の敵の数を求めるプログラム
問題の概要2次元のグリッド(行列)が与えられ、その各セルには「2」「1」「0」の3種類の値が入っています。「2」は敵、「1」は壁、「0」は空きマスを表します。この中で、爆弾を1つだけ設置して倒せる最大の敵の数を求めるのがこの問題です。爆弾の仕様は以下の通りです。爆弾は設置された地点から、同じ行と同じ列にある敵をすべて倒します。爆弾の効果は壁にぶつかった時点で止まります。爆弾を設置できるのは空きマス(0)のみです。例えば、以下のようなグリッドが入力として与えられた場合を考えてみましょう。この場合の出力は 3 になります。緑色のマスに爆弾を設置することで、最大3体の敵を倒せるからです。アルゴリズム
-
C++でアナログ時計の時針と分針の間の角度を求めるプログラム
アナログ時計の時刻を表す「時(hour)」と「分(minute)」の2つの値が与えられたとき、時針と分針がなす角度のうち、小さい方の角度を求める問題です。たとえば、hour = 12、minutes = 45 が入力された場合、答えは 112.5度 となります。解き方の考え方まず、それぞれの針がどれだけ回転するかを理解しましょう。時計盤は一周360度です。時針は12時間で360度回るため、1時間あたり30度動きます。さらに分の経過に合わせて少しずつ進むので、1分あたり0.5度ずつ移動します。分針は60分で360度回るため、1分あたり6度ずつ移動します。この性質をもとに、以下の手順で角度を計算で
-
C++で通信塔のグループ数を求める方法|DFSによる連結成分カウントの実装例
問題の概要 2次元のバイナリ行列が与えられます。各セルの値は次の意味を持ちます。 1 … そのセルに通信塔が存在する 0 … 空きセルである 通信塔同士は、以下のルールに従って互いに通信できます。 塔Aと塔Bが同じ行または同じ列に配置されている場合、直接通信できます。 塔Aが塔Bと通信でき、塔Bが塔Cと通信できるなら、塔Aは塔Cとも通信できます(推移律)。 この条件のもとで、互いに通信可能な塔の集合(グループ)の総数を求めます。これはグラフ理論でいう連結成分の数を数える問題にほかなりません。 入力例 110 001 101 この行列の場合、5つの塔すべてが行・列を介して相互に
-
C++で連続する重複文字を削除する最小コストを求めるプログラム
小文字だけで構成された文字列 s と、非負整数のリスト nums があるとします。両者の長さは同じです。文字 s[i] を削除するにはコスト nums[i] がかかり、削除後は s[i] と nums[i] の両方が取り除かれます。このとき、連続して繰り返される文字をすべてなくすために必要な最小コストを求めるのが本問題です。 入力例と出力例 たとえば、入力が s = xxyyx、nums = [2, 3, 10, 4, 6] の場合を考えてみましょう。このとき出力は 6 になります。s[0](x)と s[3](y)を削除すると、残りの文字列は xyx となり連続する重複がなくなります。このと
-
C++でnの階乗(n!)の末尾ゼロの個数を求める方法
問題概要整数nが与えられたとき、n!(nの階乗)の末尾に連続して並ぶゼロ(後続ゼロ)の個数を求めることを考えます。例えば、入力が n = 20 の場合、20! = 2432902008176640000 となるため、末尾にはゼロが4個連続しており、出力は4になります。解法の考え方末尾のゼロの個数は、階乗の計算結果に含まれる「10」の個数で決まります。10 = 2 × 5 であるため、因数2と因数5のペアの数がそのままゼロの個数に対応します。そして階乗の中では、因数2は因数5よりも必ず多く現れるため、因数5の出現回数を数えるだけでよいことが分かります。具体的には、以下の手順で求めます。count
-
C++で解く:重複しない2つの部分配列の最大合計を求める効率的なアルゴリズム
整数型の配列 A が与えられたとき、互いに重なり合わない2つの部分配列(サブアレイ)に含まれる要素の合計の最大値を求めることを考えます。ここで、2つの部分配列の長さはそれぞれ L と M です。 問題の定義 より正確には、次の式を満たす最大の V を求めます。 V = (A[i] + A[i+1] + … + A[i+L−1]) + (A[j] + A[j+1] + … + A[j+M−1]) このとき、インデックスは以下のいずれかの条件を満たす必要があります。 0 ≤ i < i + L − 1 < j < j + M − 1 < 配列Aのサイズ(長さLの部分配列が左、長さMの部分配列が
-
C++で解く「石を動かして連続配置にする II」― 移動回数の最小値と最大値を求める
問題概要 無限に続く数直線を考えます。i 番目の石の位置は配列 stones で与えられ、stones[i] が i 番目の石の座標を表します。最も小さい位置、または最も大きい位置にある石を「端点の石」と呼びます。各ターンでは、端点の石を1つ選び、それ以上端点にならないように、まだ占有されていない空き位置へ移動させます。 例えば stones = [1,2,5] の場合、位置 5 にある端点の石は動かせません。0 や 3 など、どの空き位置に置いてもその石は再び端点になってしまうためです。 この操作を繰り返し、すべての石が連続した位置に並んでこれ以上手が打てなくなった時点で、ゲームは終了しま
-
C++で二分木の「いとこ」ノードを判定するアルゴリズム
二分木のいとこ(Cousins)とは二分木において、根ノードは深さ0に位置し、深さkのノードの子は深さk+1に位置するとします。このとき、二分木内の2つのノードが同じ深さを持ち、かつ親が異なる場合、その2つのノードは「いとこ(cousins)」であると定義されます。木の中のすべての値は一意であり、異なる2つのノードの値としてxとyが与えられます。私たちの課題は、値xとyに対応するノードがいとこの関係にあるかどうかを判定することです。例えば、次のような二分木が与えられたとします。x = 5、y = 4 の場合、出力は true となります。両者とも深さ2にありますが、親がそれぞれ異なるためです。
-
【C++】腐ったオレンジ問題の解法 ― 全てのオレンジが腐るまでの最小時間を求める
問題概要あるグリッド(2次元配列)が与えられ、各セルには以下の3つの値のいずれかが格納されています。0:空のセル1:新鮮なオレンジ2:腐ったオレンジ毎分、腐ったオレンジに上下左右で隣接している新鮮なオレンジは腐っていきます。このとき、グリッド内に新鮮なオレンジが1つもなくなるまでに経過する必要のある最小の時間(分)を求めてください。すべてのオレンジを腐らせることが不可能な場合は -1 を返します。例えば、入力が [[2,1,1],[1,1,0],[0,1,1]] の場合、出力は 4 となります。解法のアプローチこの問題は、腐敗の広がりを毎分シミュレーションすることで解くことができます。手順は以
-
C++で解く「Lonely Pixel II」― 条件を満たす黒ピクセルを数えるアルゴリズムと実装例
問題の概要白(W)と黒(B)のピクセルで構成された画像が与えられ、特定の条件を満たす「孤独な黒ピクセル」の総数を求めるのがこの問題の目的です。対象となるのは行R・列Cの位置にある黒ピクセルで、次の2つのルールをすべて満たしている必要があります。行Rと列Cには、それぞれちょうどN個の黒ピクセルが含まれていること列Cに黒ピクセルを持つすべての行が、行Rと完全に同一であること画像は「B」(黒)と「W」(白)からなる2次元のchar型配列として表現されます。入力例WBWBBWWBWBBWWBWBBWWWBWBWN = 3 のとき、出力は 6 になります。これは1列目と3列目(0始まり)に存在するすべて
-
C++で文字列から二分木を構築する方法
括弧と整数から構成される文字列が与えられたとき、その文字列から二分木を構築する問題を考えてみましょう。入力文字列全体が一つの二分木を表しており、整数の後に0個、1個、または2組の括弧が続く形式になっています。整数はルート(根)ノードの値を表し、各括弧のペアは同じ構造を持つ子の部分木を含んでいます。問題の例例えば、入力が 4(2(3)(1))(6(5)) のような文字列だった場合、出力は [3,2,1,4,5,6](中順走査・inorder traversal の結果)となります。解決アプローチこの問題を解くために、以下の手順に従います。再帰関数 solve() を定義します。引数として文字列
-
C++でトーナメントの対戦カードを出力する方法
n個のチームがあるとしましょう。コンテストをより面白くするために、常に強いチームと弱いチームを対戦させる戦略を採用します。たとえば、ランキング1位の最強チームと最下位のn位のチームを対戦させるといった具合です。この記事では、そのような戦略に基づいた最終的な対戦カード(マッチアップ)を文字列形式で求める方法を解説します。問題の概要各チームは初期ランキングを表す1からnまでの正の整数で与えられます。ランク1が最も強いチーム、ランクnが最も弱いチームです。対戦カードの表現には、括弧「(」「)」をペアのグループ化に、カンマ「,」を区切りに使用します。各ラウンドのペアリングでは、必ず強いチームと弱いチー
-
C++で二分木の境界を反時計回りに求める方法
問題の概要 二分木が与えられたとき、根(ルート)から開始して反時計回りに境界(バウンダリ)の値をすべて求めます。境界には左境界・葉ノード・右境界が含まれますが、重複するノードは1度だけ出力します。 左境界:根から最も左側にあるノードまでの経路 右境界:根から最も右側にあるノードまでの経路 根に左部分木(または右部分木)がない場合、根そのものが左境界(または右境界)になります たとえば、次のような二分木が入力として与えられたとします。 この場合の出力は [1, 2, 4, 7, 8, 9, 10, 6, 3] となります。 解法のアプローチ この問題は、処理を次の3つの役割に分けて考えると
-
【C++】配列を合計が等しい4つの部分配列に分割できるか判定する方法
問題概要n個の整数からなる配列が与えられたとき、以下の条件を満たす三つ組 (i, j, k) が存在するかどうかを判定する問題を考えてみましょう。0 < i、i + 1 < j、j + 1 < k < n − 1 を満たすこと部分配列 (0, i−1)、(i+1, j−1)、(j+1, k−1)、(k+1, n−1) の4つの合計がすべて等しいことここで、部分配列 (L, R) とは、元の配列のインデックス L の要素からインデックス R の要素までを切り出した範囲を意味します。例として、入力が [1,2,1,2,1,2,1] の場合を考えてみます。このとき i = 1
-
C++で解く二分木の最長連続シーケンス II
この記事では、二分木が与えられたときに、その木の中で最長連続パス(Longest Consecutive Path)の長さを求めるアルゴリズムをC++で実装する方法を解説します。問題の概要二分木において、以下の条件を満たすパスのうち最も長いものの長さを見つけます。パスは増加方向でも減少方向でも構いません。つまり [1, 2, 3, 4] と [4, 3, 2, 1] はどちらも有効なパスですが、[1, 2, 4, 3] のように順序が混在したものは無効です。パスは子 → 親 → 子の順序であってもよく、必ずしも親から子への一方向である必要はありません。例として、次のような二分木を考えます。この
-
C++で連結文字列をループ状に分割し、辞書順最大の文字列を求める方法
問題の概要 文字列のリストが与えられ、これらをループ状につなぎ合わせることを考えます。このとき、各文字列はそのまま使うか反転するかを選択できます。考えられるすべてのループの中から、ループを1箇所切断して通常の文字列に戻したときに、辞書順で最大になる文字列を見つけるのが目的です。 具体的には、次の2つのフェーズを経て辞書順最大の文字列を求めます。 連結フェーズ:すべての文字列を1つのループに連結します。一部の文字列は反転しても構いませんが、並び順は与えられた順序のまま保ちます。 切断フェーズ:ループ上の任意の位置に切断点を1つ設け、その文字から始まる通常の文字列を作ります。生成可能なすべての
-
C++でマトリックス内の連続する1の最長ラインを求める方法(動的計画法)
問題概要 0と1だけで構成されたバイナリ行列 M が与えられます。この行列の中から、連続した1が並ぶ最長のラインの長さを求めてください。ラインの向きは、水平方向・垂直方向・斜め(対角線)方向・反斜め(逆対角線)方向のいずれかです。 例として、次のような入力を考えてみましょう。 011001100001 この場合の出力は 3 です。(0,1) → (1,2) → (2,3) と、左上から右下へ向かう対角線上に1が3つ連続して並んでいるためです。 解法アプローチ:動的計画法(DP) この問題は、4つの方向それぞれについて「そのセルを終点とする連続する1の長さ」を記録する動的計画法で効率的に解くこ