-
C++で条件arr[i+1] > arr[i]を満たす要素を最大化するアルゴリズム
はじめに本記事では、C++を用いて「隣接する2つの要素が arr[i+1] > arr[i] を満たすように配列を並べ替え、その条件を満たすインデックスの数を最大化する」問題について解説します。問題文N個の整数からなる配列が与えられます。この配列の要素を並べ替えて、「次の要素が前の要素より大きい」という条件、すなわち arr[i+1] > arr[i] を満たす位置の数をできるだけ多くしてください。入力例入力配列が {300, 400, 400, 300} の場合、並べ替え後の配列は次のようになります。{300, 400, 300, 400}この並べ方では、条件 arr[i+1]
-
C++で2つの配列から作れるペアの最大数を求めるアルゴリズム
問題の概要同じサイズ N を持つ2つの配列が与えられたとき、各配列から1つずつ要素を選んでペアを作り、そのペアの最大数を求めます。ただし、以下の条件を満たす必要があります。各配列の要素は最大1回しか使用できないペアを構成する2つの要素の絶対差が指定された値 K 以下であること入力例たとえば、次のような入力が与えられたとします。arr1[] = {3, 4, 5, 2, 1} arr2[] = {6, 5, 4, 7, 15} k = 3この場合、絶対差が3以下になるペアは次の4組です。(1, 4), (2, 5), (3, 6), (4, 7)したがって、答えは 4 となります。アルゴリズムの
-
C++で最小ヒープから最大要素を効率的に求める方法
問題の概要最小ヒープ(min-heap)が与えられたとき、その中に含まれる最大要素を見つけるプログラムを作成します。例入力として次のような最小ヒープが与えられたとします。この場合、最大要素は 55 となります。アルゴリズムの考え方最小ヒープには重要な性質があります。親ノードは必ず子ノード以下の値を持つこの性質から、次のように結論づけられます。葉以外のノード(内部ノード)は、少なくとも1つの子ノードより小さい値を持つため、最大要素になることはないしたがって、最大要素は必ず葉ノードの中に存在するつまり、配列で表現されたヒープにおいて、インデックス n/2 以降(葉ノードに相当する部分)だけを走査す
-
C++で2進表現における隣接する2つの1の間の最大0の個数を求める方法
問題概要 整数 n が与えられたとき、その2進表現において隣り合う2つの1の間に存在する0の最大個数を求めるのが課題です。ただし、2進表現に1が2つ未満しか含まれていない場合は -1 を返します。 具体例 入力が 35 の場合、2進表現は次のようになります。 00100011 この2進表現では、隣接する2つの1の間に3つの0が存在します。したがって、答えは 3 となります。 アルゴリズム この問題はビットシフト演算子を使うことで効率的に解けます。n の2進表現の中から隣接する2つの1の位置を見つけ、その位置の差を最大化することを考えます。 数値が 0 または 2 のべき乗である場合(1が1
-
C++で正方行列の最大値と最小値を効率的に求める方法
問題文n×n の正方行列が与えられたとき、その行列に含まれる要素の中から最大値と最小値を求めるプログラムを作成します。例例として、次のような 3×3 の行列が与えられたとします。{{15, 17, 19}, {5, 1, 7}, {14, 5, 16}}この場合、最小値は 1、最大値は 19 となります。アルゴリズム行列の各行について、行の先頭の要素と行の末尾の要素のように、対になる2つの要素を選びます。選んだ2つの要素を比較し、小さい方を現在の最小値と、大きい方を現在の最大値と照らし合わせます。必要に応じて最小値・最大値を更新します。2つの要素を処理するのに必要な比較は3回なので、行列全体を
-
C++で配列内のペアから得られる最大のビット単位AND(論理積)値を求めるアルゴリズム
問題文 n個の正の整数からなる配列が与えられます。この中から任意の2つの要素を選んだペアについて、ビット単位AND(論理積)の最大値を求めるのが本問題です。 例 入力配列が {10, 12, 15, 18} の場合、ビット単位ANDの最大値は 12 となります。これは 12 (1100) と 15 (1111) のANDを取った結果 1100(= 12)が最も大きいためです。 アルゴリズム ビット単位ANDでは、両方のビットが1である場合にのみ、結果のその桁が1になります。この性質を利用すると、以下のような貪欲法で効率よく最適解を求められます。 最上位ビット(MSB)から順に、そのビッ
-
C++で四辺形の最大面積を求める方法
問題文 四辺形の4つの辺 a、b、c、d が与えられたとき、それらの辺から構成できる四辺形の最大面積を求めることを考えます。 アルゴリズム この問題は、古代インドの数学者ブラーマグプタ(Brahmagupta)による次の公式を利用することで解くことができます。 √(s−a)(s−b)(s−c)(s−d) ここで、s は半周長(semi-perimeter)と呼ばれる値であり、次のように計算します。 S = (a + b + c + d) / 2 なお、ブラーマグプタの公式は本来、円に内接する四辺形に対して成立するものですが、与えられた4つの辺の長さを持つすべての四辺形の中では、円に内接する四
-
C++で元の順序を保ちながら2つの配列から最大要素のみで構成される配列を作成する方法
問題文同じサイズを持つ2つの配列 A[] と B[] が与えられています。この課題では、同じサイズの第3の配列を作成します。結果の配列には、両方の配列から合計 n 個の最大要素が含まれる必要があります。まず A[] から選ばれた要素を先頭に配置し、その後に B[] から選ばれた要素を続けます。重要なのは、選ばれた要素が元の配列内での登場順序を維持しなければならないという点です。また、両方の配列に共通する要素が存在する場合は、結果配列には1つだけ含め、優先順位は A[] の側に与えます。具体例入力配列が次の通りだったとします。arr1[] = {9, 17, 2, 25, 6} arr2[] =
-
【C++】サイズがX以上Y以下の部分配列の最大平均を求める方法
問題の概要整数型の配列 arr[] と、2つの整数 X・Y が与えられます。求めるのは、サイズが X 以上 Y 以下となる連続した部分配列の中から、平均値が最大になるものを見つけることです。例入力配列が {2, 10, 15, 7, 8, 4}、X = 2、Y = 3 の場合、次のようにして最大平均 12.5 を得ることができます。(10 + 15) / 2 = 12.5このケースでは、サイズ2の部分配列 {10, 15} の平均が、条件を満たすすべての部分配列の中で最も高くなります。アルゴリズムX から Y までの各サイズについてすべての部分配列を順に調べ、その中で最大の平均値を求めます。計
-
C++で配列を最大K個に分割して平均の合計を最大化する方法
問題概要 数値の配列 A が与えられます。この配列を最大 K 個の隣接する(空でない)グループに分割し、スコアを「各グループの平均値の合計」と定義します。このとき、達成できる最大スコアを求めるのが本問題です。 入力例 入力配列が {9, 2, 5, 3, 10} の場合、たとえば次のように分割できます。 {9} {2, 5, 3} {10} このときの平均の合計は次のとおりです。 9 + (2 + 5 + 3) / 3 + 10 = 22.33 アルゴリズム(メモ化再帰) この問題は、メモ化(記憶化)再帰を使うことで効率よく解くことができます。 memo[i][k]:A[i]〜A[n-1]
-
C++で指定範囲内の最大ビットANDペアを求める方法
問題の概要範囲 [L, R] が与えられたとき、L ≤ X < Y ≤ R を満たす整数のペア (X, Y) の中から、ビットごとのAND(論理積)である X & Y が最大になる組み合わせを見つけ、その値を出力するのが課題です。具体例L = 1、R = 10 の場合を考えてみましょう。このとき最大のビットAND値は 8 となり、次のように求められます。1000 # 8 の2進数表現 & 1001 # 9 の2進数表現 ---- 1000 # 最終結果 = 8アプローチ最もシンプルな方法は、L から R までのすべての数値ペアを総当たりで調べることです。各ペア
-
C++で0またはnだけで構成される3×3行列の最大行列式を求める方法
問題概要正の整数 n が与えられたとき、各要素が 0 または n のいずれかで構成される 3×3 行列の中から、最大の行列式を持つ行列を見つけるのが本記事のテーマです。例n = 15 の場合、たとえば次のような行列が考えられます。{{15, 15, 0}{0, 15, 15}{15, 0, 15}}要素が 0 か n のみで構成される任意の 3×3 行列において、行列式の最大値は 2 × n³ であることが証明されています。したがって、この場合の答えは以下の通りです。2 × 15³ = 6750なぜ最大値が 2n³ になるのか各要素が 0 または n の行列は、各行から n をくくり出すことで
-
C++で木構造から辺を削除し、全ての連結成分が偶数頂点となる森を作る最大削除数を求める
問題概要 頂点数が偶数である無向木(ツリー)が与えられます。この木からできるだけ多くの辺を取り除き、削除後の森(フォレスト)を構成する各連結成分の頂点数がすべて偶数になるようにします。求めるのは、削除できる辺の最大本数です。 例 上図の木では、赤色で示した 0–2 と 0–4 の2本の辺を削除すると、各連結成分の頂点数がすべて偶数になります。これがこの木における削除可能な辺の最大本数です。 考えるポイント 木全体の頂点数が偶数であるため、サイズが奇数の部分木は必ず偶数個存在し、それらは最終的にどこかで結合して偶数サイズの成分を形成します。つまり、DFSで部分木のノード数を数え、そのサイズが
-
C++で二分探索木(BST)の2つのノード間の最大要素を求める方法
問題文 N個の要素を持つ配列と、その配列に含まれる2つの整数 A、B が与えられます。まず、配列の要素 arr[0] から arr[n-1] を順番に挿入して二分探索木(BST:Binary Search Tree)を構築します。その上で、ノード A からノード B への経路上に存在する最大の要素を見つけることが本問題の目的です。 例 配列が {24, 23, 15, 36, 19, 41, 25, 35} の場合、構築されるBSTは次のようになります。 ここで A = 19、B = 41 とした場合、この2つのノード間の最大要素は 41 となります。 アルゴリズム この問題は、BST
-
C++で小屋のパターンを出力するプログラム
このチュートリアルでは、星印(*)を使ってコンソールに小屋のパターンを出力するC++プログラムを解説します。 この問題では、出力する小屋の幅 N が与えられます。求められるのは、指定された幅に合わせて星印で小屋の外枠を描き、さらに小屋の内部に縦線(|)と下線(_)を使ってドアを表現することです。 アルゴリズムのポイント 入力値 N が偶数の場合は 1 を加えて奇数に調整し、図形の対称性を保ちます。 屋根の傾斜は「行番号+列番号」「列番号−行番号」が特定の値になるかどうかで判定し、星印を配置します。 壁や床は、最上部・最下部・左右両端の座標条件によって星印を描き分けます。 ドアは N/7 を基
-
C++で面白いパターンを出力するプログラムの作成方法
このチュートリアルでは、指定された面白いパターンを出力するC++プログラムについて解説します。この問題では、パターンの半分の幅が入力として与えられます。私たちのタスクは、その幅に応じてパターンを出力することです。このパターンの特徴は、左右の部分が鏡像の関係になっている点にあります。いわゆる「蝶型(バタフライ)パターン」と呼ばれるものです。パターンの出力方法パターンは上半分と下半分に分けて出力します。各行では、左半分と右半分をそれぞれ別の条件で判定しながら、アスタリスク(*)または空白を出力していきます。上半分では、行番号と列番号の大小関係を利用して、左側は三角形を広げ、右側はそれを鏡写しにした
-
C++で逆ダイヤモンドパターンを出力するプログラムの作り方を解説
はじめに このチュートリアルでは、C++を使って逆ダイヤモンドパターンをコンソールに出力するプログラムについて解説します。 入力として整数 N が与えられ、高さが 2N-1 行となる逆ダイヤモンド型のパターンを表示するのが目標です。星印(*)と空白を組み合わせて、中央がくぼんだ美しい逆ダイヤモンドの形を作り上げます。 パターンの構造を理解する 逆ダイヤモンドパターンは、上半分と下半分の2つの部分に分けて考えると理解しやすくなります。 上半分: 行が下に進むごとに、左右の星(*)が1つずつ減り、中央の空白が2つずつ広がっていきます。 下半分: 上半分とは逆に、行が進むごとに星が1つずつ増え、中
-
C++でカイト(凧)パターンを出力するプログラムの作り方
このチュートリアルでは、指定されたカイト(凧)型のパターンをコンソールに出力するC++プログラムについて解説します。ここでは入力として N=5 を使用します。全体の出力は 2N+1 = 11 行で構成され、そのうち9行が上側のダイヤモンド(ひし形)構造、残りの2行が下側の不完全なダイヤモンド構造に対応します。各行ごとに出力する空白の数と「$」記号の数を制御することで、凧のような形状を作り出しています。サンプルコード#include <bits/stdc++.h>#include <stdlib.h>using namespace std;int main(){ 
-
C++で文字列の最後の10行を出力するプログラム
はじめに本記事では、C++を使って文字列の最後の10行を出力する方法について詳しく解説します。ここでは、改行文字(\n)で区切られた複数行の文字列が与えられるものとします。このとき、文字列の末尾から数えて10行分の内容だけを取り出して出力するのが今回の目的です。想定される場面たとえば、ログファイルや長いテキストデータの「末尾の一部だけ」を表示したい場合など、この処理は実際の開発でもよく使われます。Linuxのtailコマンドのような動作を自前で実装するイメージです。アルゴリズムの考え方この問題は、以下の手順で解決できます。strrchr()関数を使って、文字列内で最後に現れた改行文字の位置を見
-
C++で文字列の末尾N行を出力するプログラムを解説
はじめにこのチュートリアルでは、C++を使って文字列の末尾(最後)のN行を出力するプログラムについて解説します。ここでは、改行文字(\n)で各行の始まりを示す複数行の文字列と、末尾から出力したい行数Nが与えられます。私たちのタスクは、文字列の終わりから数えてN行分をすべて出力することです。アルゴリズムのポイントこの問題を効率的に解くためには、以下の手順が有効です。1. strrchr関数を使って、文字列内で最後に出現する改行文字の位置を見つけます。2. その位置から前方に向かって走査し、改行文字を見つけるたびに行数をカウントします。3. 必要な行数Nに達した時点で、その位置以降の文字列を出力し