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

C++で数字の配列から作れる3の倍数の最大値を求める方法

問題の概要

さまざまな数字が格納された配列が与えられます。その中からいくつかの数字を選び、任意の順序で連結することで作成できる「3の倍数」の最大値を求めるのが課題です。答えは非常に大きな数になる可能性があるため、文字列として返します。答えが存在しない場合は空文字列を返してください。

例えば、入力が [7, 2, 8] の場合、出力は 87 となります。

解法のアプローチ

この問題は「3の倍数の性質」を利用することで効率的に解けます。ある整数が3の倍数であるための必要十分条件は、その各桁の合計が3で割り切れることです。そこで、数字を3で割った余り(0・1・2)ごとにグループ分けし、合計が3の倍数になるよう最小限の数字を取り除く方針で解きます。

手順

  • 3行からなる2次元配列 d を定義する
  • 配列 digits を降順にソートする
  • sum := 0 で初期化する
  • i := 0 から digits のサイズ未満の間、以下を繰り返す
    • x := digits[i]
    • d[x mod 3] の末尾に digits[i] を追加する
    • sum := sum + x
    • sum := sum mod 3
  • sum が 0 でない場合、以下を行う
    • d[sum] のサイズが 0 の場合
      • rem := 3 - sum とする
      • d[rem] のサイズが 2 未満なら空文字列を返す
      • d[rem] の末尾から要素を2つ削除する
    • それ以外の場合
      • d[sum] の末尾から要素を1つ削除する
  • ret := 空文字列 で初期化する
  • i := 0 から 3 未満の間、以下を繰り返す
    • j := 0 から d[i] のサイズ未満の間、ret に d[i][j] を文字列として連結する
  • ret を降順にソートする
  • ret のサイズが 0 でなく、ret[0] が '0' と等しい場合は "0" を返す
  • ret を返す

アルゴリズムのポイント

合計が3で割り切れない場合、取り除くべき数字の候補は次の2パターンだけです。余りの合計が 1 のときは「余り1の数字を1個」または「余り2の数字を2個」を、余りの合計が 2 のときは「余り2の数字を1個」または「余り1の数字を2個」を取り除けばよいことになります。降順ソートしておけば配列の末尾には最も小さい数字が集まるため、末尾から削除することで結果の数値を最大に保てます。また、結果が "00" のようになるケースに備えて "0" への正規化も行っています。

C++実装例

以下の実装で、より理解を深められます。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
    string largestMultipleOfThree(vector<int>& digits) {
        vector<vector<int>> d(3);
        sort(digits.begin(), digits.end(), greater<int>());
        int sum = 0;
        for (int i = 0; i < digits.size(); i++) {
            int x = digits[i];
            d[x % 3].push_back(digits[i]);
            sum += x;
            sum %= 3;
        }
        if (sum) {
            if (!d[sum].size()) {
                int rem = 3 - sum;
                if (d[rem].size() < 2)
                    return "";
                d[rem].pop_back();
                d[rem].pop_back();
            }
            else {
                d[sum].pop_back();
            }
        }
        string ret = "";
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < d[i].size(); j++) {
                ret += to_string(d[i][j]);
            }
        }
        sort(ret.begin(), ret.end(), greater<int>());
        if (ret.size() && ret[0] == '0')
            return "0";
        return ret;
    }
};
main(){
    Solution ob;
    vector<int> v = {7,2,8};
    cout << (ob.largestMultipleOfThree(v));
}

入力

{7,2,8}

出力

87
  1. C++で二分木における最大部分木の合計を求める方法

    この問題では、二分木(バイナリツリー)が与えられます。私たちのタスクは、木の中で最も大きな合計値を持つ部分木を見つけることです。 問題の概要 二分木には正の値と負の値が混在しています。その中から、ノードの合計が最大になる部分木を特定する必要があります。 例で問題を理解しよう 出力: 13 説明: 左部分木の合計:7 右部分木の合計:1 木全体の合計:13 このように、根を含む木全体の合計である「13」が最大の部分木の合計となります。 解法のアプローチ この問題を解くためには、後順走査(ポストオーダー走査)を利用します。手順は以下の通りです。 左部分木と右部分木それぞれのノードの合計を再

  2. C++でSTLのaccumulate()関数を使って配列の要素の合計を求める方法

    この記事では、C++のSTL(標準テンプレートライブラリ)を使用して、配列のすべての要素の合計を求める方法を解説します。例えば、配列が [12, 45, 74, 32, 66, 96, 21, 32, 27] の場合、合計は 405 になります。このような合計計算を簡単に行うには、accumulate() 関数を使用します。この関数は <numeric> ヘッダーファイルで定義されており、指定した範囲内の要素を順番に加算していくことができます。accumulate() 関数の基本構文accumulate(first, last, init) の形式で呼び出します。第1引数と第2引数