-
C++で長さkの最大平均サブ配列を求める方法【累積和によるO(n)実装】
問題概要 この問題では、正と負の値が混在するサイズnの配列 arr[] と整数 k が与えられます。求めるのは、長さkのサブ配列の中で平均が最大になるものです。 なお、要素数が同じであれば「平均が最大のサブ配列」と「合計が最大のサブ配列」は一致するため、この問題は「長さkのサブ配列のうち合計が最大のものを探す」として扱えます。 入出力例 入力:arr[] = {4, -1, 5, 6, -2, 4}、k = 3 出力:10 説明:長さ3のサブ配列のうち合計が最大となるのは {-1, 5, 6} で、その合計は10になります。 解法アプローチ:累積和を活用する この問題は累積和(prefix
-
C++で比較演算子を使わずに配列の最大値を求める方法
この問題では、正の整数からなるサイズ n の配列 arr[] が与えられます。求めたいのは、関係演算子(< や > などの比較演算子)を使用せずに、配列内の最大値を見つけることです。問題の例入力: arr[] = {5, 1, 6, 7, 8, 2}出力: 8解法のアプローチ比較演算子を使わずに値の大小を比べるには、「繰り返し減算」を利用します。2つの値を同時に1ずつ減らしていき、どちらか一方でも0より大きい間は処理を続けます。最後まで残った数が大きい方の値というわけです。具体的には、while (x || y) というループの中で x と y をそれぞれ1ずつ減算し、ループが回っ
-
C++で行列内の同じ長方形領域の合計を持つセルを出力する方法
問題の概要 この記事では、整数値を要素とする m×n サイズの行列 mat が与えられたとき、同じ長方形領域の合計を持つセルを行列から出力するプログラムをC++で作成します。 問題の説明: 行列の中からあるセルを見つけ出し、そのセルを境界として得られる2つの部分行列(左上の領域と右下の領域)の合計が、残りのすべての要素の合計と等しくなるようにします。 言い換えると、セル (a, b) において、mat[0][0] から mat[a][b] までの部分行列と、mat[a][b] から mat[m-1][n-1] までの部分行列の合計(重複するセルは1回だけカウント)が、それ以外の要素の合計と一致
-
【C++】指定範囲内のBSTキーをO(1)空間で出力する方法 ― モリス走査の活用
問題の概要 この問題では、2つの値 k1 と k2(k1 < k2)、および二分探索木(BST)のルートが与えられます。目的は、指定された範囲内に存在するBSTのキーを出力するプログラムをC++で作成することです。 問題の説明: 木に含まれるすべてのキーのうち、k1 以上 k2 以下の値を持つものを昇順に出力します。 入出力例 入力: k1 = 4、k2 = 12 出力: 6, 7, 9 解決アプローチ この種の問題は、一般的には中順走査(inorder traversal)を使えば簡単に解くことができます。しかし、再帰呼び出しやスタック・キューを利用する通常の実装では、空間計算量が
-
C++で一方の文字列を別の文字列に変換するすべての方法を出力する
この問題では、2つの文字列 str1 と str2 が与えられます。私たちのタスクは、一方の文字列を別の文字列に変換するすべての可能な方法を出力するプログラムを作成することです。 問題の説明:ここでは、str1 を str2 に変換できるすべての方法を見つける必要があります。変換の際には、次の3つの操作のいずれかを実行できます。 挿入(Insert) 削除(Remove) 置換(Replace) 具体例を使って問題を理解しましょう。 入力:str1 = kfeod、str2 = kfcadq 出力 Way1:d の後に q を挿入。c を e に置換。o を a に置換。 解
-
C++で配列内のすべてのペアの和のXORを計算する方法
問題の概要 この問題では、サイズnの配列arr[]が与えられます。私たちのタスクは、配列内のすべてのペアについて要素の和を求め、それらの和のXORを計算するプログラムを作成することです。 例で問題を理解しましょう 入力: arr[] = {5, 7, 9} 出力: 22 説明: (5+5) ^ (5+7) ^ (5+9) ^ (7+5) ^ (7+7) ^ (7+9) ^ (9+5) ^ (9+7) ^ (9+9) = 22 解法1: 単純なアプローチ(ネストしたループ) 最もシンプルな解法は、ネストしたループを使用して配列からすべての可能なペアを生成し、各ペアの和のXORを順に計算していく方
-
サブセットの総和 – C++での動的計画法による効率的な解法
問題概要この問題では、サイズ 2n の配列 arr[] が与えられます。目的は、動的計画法(DP)を用いて「サブセットの総和(Sum over Subsets)」を求めるプログラムを作成することです。具体的には、次の関数 F(x) を計算します。F(x) = Σ Ai (ただし x & i == i を満たすすべての i に対する和)つまり、i が x のビット単位での部分集合であるような Ai の合計を求めるという意味です。入力例と出力例入力: A[] = {5, 7, 1, 9}, n = 2出力: 5 12 6 22説明: n = 2 のとき、x は 0、1、2、3 の 4 通り
-
C++で級数 1+(1+3)+(1+3+5)+…+(1+3+5+…+(2n−1)) の総和を求める方法
この問題では、整数 n が与えられ、級数 1 + (1+3) + (1+3+5) + (1+3+5+7) + … + (1+3+5+7+…+(2n−1)) の総和を求めるプログラムを作成します。 問題例 入力: n = 5 出力: 55 つまり、ユーザーから数値「n」を受け取り、この級数の総和を計算して出力するのが課題です。 まず、この級数がどのような構造になっているのかを確認しましょう。 n = 1 のとき、級数は「1」になります。 n = 2 のとき、最終項の 2n−1 は 2×2−1 = 3 となるため、級数は「1 + (1+3)」になります。 n の値2n−1級数の形111231
-
C++で最長共通部分列(LCS)をすべて辞書式順序に出力する方法
この記事では、2つの文字列 str1 と str2 が与えられたとき、それらの最長共通部分列(LCS:Longest Common Subsequence)をすべて辞書式順序で出力するC++プログラムの作成方法を解説します。問題の例具体的な入力と出力の例を見てみましょう。入力:str1 = gfare、str2 = rfare出力:fareこの場合、fare が両方の文字列に共通する最長の部分列となり、これが出力結果となります。解決アプローチこの問題は次の手順で解くことができます。LCSの長さを求める:動的計画法(DP)を用いたメモ化再帰により、最長共通部分列の長さを計算し、結果を二次元配列(
-
C++で数値を「A」と「B」の文字列として辞書式順序に出力する方法
この問題では、数値 N が与えられ、それを「A」と「B」のみで構成される文字列として辞書式順序(lexicographic order)で出力するプログラムを作成します。 「A」と「B」による数値の表現 すべての数値を「A」と「B」の文字列で表現すると、以下のようになります。 1 = A2 = B3 = AA4 = AB5 = BA6 = BB7 = AAA8 = AAB 問題を理解するための例 入力:N = 12 出力:BAB 解決アプローチ 「A」と「B」からなる文字列は、2進数とよく似た構造を持っています。まず、次の性質を利用して文字列の長さを求めます。つまり、長さ1の文字列は2個(N=
-
C++開発におけるリスク管理の原則とパラダイム
リスク管理(Risk Management)とは、システム内で利用可能なすべてのリソースを適切に管理し、それらを最大限に活用するためのアプローチです。 プロジェクトマネージャーは、あらゆるカテゴリからリスクを分析します。プロジェクトの実行環境(ランタイム環境)では、作業の進行中にさまざまなリスクが発生する可能性があります。 リスク管理の5つの基本原則 リスク管理には、次の5つの基本原則があります。 全体視点(グローバル・パースペクティブ):解決すべきシステムやビジネス上の問題を踏まえてソフトウェアのリスク分析を行います。この分析では、より大きなシステム全体の定義、設計、実装を考慮に入れます
-
【C++】エラトステネスの篩で最小素因数を前計算し、複数クエリをO(log n)で高速に素因数分解する方法
本記事では、複数のクエリに対して高速に素因数分解を行うプログラムをC++で実装する方法を解説します。一般的な素因数分解の手法では、1回の計算にO(√n)の時間がかかります。クエリの数が増えると、この計算コストが積み重なり、全体の処理時間が大幅に膨らんでしまうのが課題です。そこで、エラトステネスの篩(ふるい)を活用することで、1クエリあたりO(log n)という非常に高速な素因数分解を実現します。基本概念のおさらい解説に入る前に、重要な2つの概念を確認しておきましょう。素因数分解とは素因数分解とは、ある整数を素数のみの積の形で表すことです。ここで含まれるのは素数の因子だけであり、合成数(素数同士
-
C++で二分木の最大レベル和を求める方法
問題概要 この問題では、正と負の値を含む二分木が与えられます。私たちのタスクは、二分木におけるレベル和の最大値を見つけることです。 問題の説明: 与えられた二分木に対して、各レベルに存在するすべてのノードの値の合計を計算し、その中で最も大きい値を返します。 具体例を使って問題を理解しましょう。 入力: 出力: 5 説明: レベル1の要素の合計:3 レベル2の要素の合計:-3 + 4 = 1 レベル3の要素の合計:5 - 1 + 6 - 5 = 5 各レベルの合計は「3」「1」「5」となるため、最大のレベル和は 5 となります。 解法アプローチ この問題を効率的に解くには、レベル順走査(幅優先
-
C++で最大K回のスワップにより作成できる最大の数を求める方法
この問題では、2つの整数値 n と k が与えられ、最大K回までのスワップ(入れ替え)によって作成できる最大の数 を求めることが課題となります。問題の概要ここで必要なのは、与えられた数字の桁を最大k回まで入れ替えたときに作れる、最も大きな数を計算することです。例で理解してみましょう入力: n = 538, k = 1出力: 835説明: 「8」と「5」を入れ替えることで、最大の数「835」が得られます。解法アプローチこの問題を解くには、数字の桁を最大k回入れ替えながら、その都度できる数が最大であるかどうかを確認する必要があります。基本的な考え方は以下の通りです。数の中から最大の桁を見つけます。
-
C++で配列から要素を削除する方法:2回の走査と1回の走査による実装を解説
本チュートリアルでは、C++を使って配列から特定の要素を削除する2つのアプローチ、「2回の走査(Two Traversals)」と「1回の走査(One Traversal)」について解説します。ここでいう「削除」とは、メモリ上からデータを消去することではなく、削除したい要素以降の要素をすべて1つ前へずらし、実質的に配列からその要素を取り除くことを指します。 2回の走査で要素を削除する方法 まず、2つのループ(走査)を使って配列から要素を削除する手順を見ていきましょう。 配列と削除対象の要素を初期化します。 要素を削除する関数を作成します。 配列を走査し、削除したい要素を検索します。 要素が
-
C++で指定したインデックス範囲[L–R]の配列要素を削除する方法
このチュートリアルでは、C++を使って配列から指定されたインデックス範囲の要素を削除する方法を解説します。アルゴリズムの基本的な考え方から、実際のコード実装・実行結果まで、順を追って見ていきましょう。 解決の手順 配列と、削除対象となるインデックス範囲 [L, R] を初期化します。 新しいインデックスを管理する変数を用意します。 配列全体を走査します。 現在のインデックスが指定範囲外であれば、その要素を新しいインデックスの位置に書き込みます。 新しいインデックスを1つ進めます。 走査が終わったら、新しいインデックス(= 残った要素数)を返します。 サンプルコード それでは、実際のコ
-
【C++】二分木から指定した値xを持つ葉ノードを削除する方法
このチュートリアルでは、二分木から指定された値を持つ葉ノード(リーフノード)を削除する方法を学びます。再帰的なアプローチを用いて、木を走査しながら条件に合致する葉ノードを取り除いていきます。解決の手順二分木のノードを表す構造体 Node を定義します。木を走査(中順・前順・後順)して、すべてのノードのデータを出力する関数を作成します。構造体を使ってノードを生成し、木を初期化します。削除対象となる値 x を設定します。指定された値を持つ葉ノードを削除する関数を作成します。この関数は、根ノードと値 x の2つの引数を受け取ります。根が NULL の場合はそのまま返します。根の左の子ノードを、削除処
-
C++で指定した値kを持つ葉ノードを削除する方法
このチュートリアルでは、二分木から指定した値を持つ葉ノード(リーフノード)を削除する方法を学びます。再帰的なアプローチを使えば、この問題はシンプルかつ効率的に解決できます。解決の手順問題を解くためのステップは以下の通りです。二分木用の Node 構造体を定義します。木を走査してすべてのデータを出力する関数(中順・前順・後順トラバーサル)を作成します。Node 構造体を使ってノードを生成し、木を初期化します。削除対象の値 k を設定します。指定した値を持つ葉ノードを削除する関数を作成します。この関数は、根ノードと値 k の2つの引数を受け取ります。根が NULL の場合はそのまま返します。左の子
-
C++で連結リストの中央ノードを削除する方法
このチュートリアルでは、C++を使って連結リスト(リンクリスト)の中央にあるノードを削除する方法を解説します。この問題の解き方は非常にシンプルです。2つのポインタを用意し、一方は1ノードずつ、もう一方は2ノードずつ進めます。速い方のポインタが連結リストの末尾に到達したとき、遅い方のポインタはちょうど中央に位置することになります。これは「フロイドの循環検出法」などでも使われる有名なテクニックで、リストの長さを事前に計算する必要がないのがポイントです。それでは、問題を解くための手順を順番に確認していきましょう。連結リストのノード用に構造体 Node を定義します。ダミーデータで連結リストを初期化し
-
C++で連結リストのM個のノードの後にN個のノードを削除する方法
このチュートリアルでは、C++を使って連結リスト(リンクドリスト)の中から、M個のノードをスキップした直後にあるN個のノードを削除する方法を解説します。アルゴリズムの手順まず、問題を解決するための全体の流れを確認しましょう。連結リストのノードを表す構造体 Node を定義します。ダミーデータを使って連結リストを初期化します。M個のノードの後にN個のノードを削除する関数を実装します。作業用ポインタをヘッドポインタで初期化します。連結リストの末尾に達するまで反復処理を行います。M個のノード分だけポインタを前進させます。続くN個のノードを削除します。ポインタを次のノードへ移動して処理を繰り返します。