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

C++でK桁を削除して最小の数値を作るアルゴリズム

負でない整数 num が文字列として与えられているとき、そこから k 桁を取り除き、残った数字で作られる新しい数をできるだけ小さくすることを目指します。例えば、入力が「1432219」で k = 3 の場合、結果は「1219」となります。

この問題は、スタックを活用した貪欲法(グリーディアルゴリズム)によって効率的に解くことができます。

解法のアプローチ

基本となる発想は、「大きい数字がその後ろの小さい数字より先に現れている箇所を優先的に削除する」というものです。文字列を左から右へ走査しながらスタックに数字を積んでいき、スタックの先頭にある数字がこれから読み込む数字より大きい場合は、それをポップ(削除)します。これを繰り返すことで桁の並びが単調増加に近づき、結果として最小の数値が得られます。

アルゴリズムの手順

  • スタック st を定義し、空の文字列 ret を用意します。
  • n := num のサイズ(文字列の長さ)とします。
  • i を 0 から n − 1 までループします。
    • k が 0 でなく、スタックが空でなく、スタックの先頭が num[i] より大きい間、スタックから要素を削除し、k を 1 減らします。
    • num[i] をスタックにプッシュします。
  • ループ後も k が 0 でない場合、残りの回数だけスタックから要素を削除します。
  • スタックが空になるまで、先頭の要素を ret に追加しながらポップします。
  • ret 文字列を反転します(スタックからの取り出し順が逆になるため)。
  • ans を空文字列とし、i := 0 とします。
  • i が ret のサイズ未満 かつ ret[i] が '0' である間、i を 1 ずつ増やします(先頭の余分な 0 を除去)。
  • i 以降の文字をすべて ans に連結し、ret := ans とします。
  • ret のサイズが 0 の場合は "0" を返し、それ以外の場合は ret を返します。

C++による実装例

以下の実装例を見ると、動作をより深く理解できます。

class Solution {
public:
    string removeKdigits(string num, int k) {
        stack<char> st;
        string ret = "";
        int n = num.size();
        for(int i = 0; i < n; i++){
            while(k && !st.empty() && st.top() > num[i]){
                st.pop();
                k--;
            }
            st.push(num[i]);
        }
        while(k--)st.pop();
        while(!st.empty()){
            ret += st.top();
            st.pop();
        }
        reverse(ret.begin(), ret.end());
        string ans = "";
        int i = 0;
        while(i < ret.size() && ret[i] == '0')i++;
        for(; i < ret.size(); i++)ans += ret[i];
        ret = ans;
        return ret.size() == 0 ? "0" : ret;
    }
};

計算量

各桁はスタックに対して高々 1 回のプッシュと 1 回のポップしか行われないため、時間計算量は O(n)、空間計算量も O(n) となります。ここで n は num の桁数です。

入力

"1432219"
3

出力

"1219"
  1. C++で解く「ジャンプゲームV」:メモ化再帰による最大訪問インデックス数の求め方

    問題の概要整数型の配列 arr と整数 d が与えられます。1ステップごとに、インデックス i から次の場所へジャンプできます。右方向: i + x(ただし i + x < n、かつ x は 1 以上 d 以下)左方向: i - x(ただし i - x >= 0、かつ x は 1 以上 d 以下)ここで n は配列のサイズです。さらに重要な制約として、インデックス i から j へジャンプできるのは、arr[i] > arr[j] であり、かつ i と j の間にあるすべてのインデックス k に対して arr[i] > arr[k] を満たす場合のみです。つまり、より低

  2. C++で約数がちょうど4個の整数の約数の総和を求める方法

    整数配列 nums が与えられたとき、その中から「約数がちょうど4個」である整数を見つけ出し、それらの約数の総和を計算する問題を考えてみましょう。もし該当する整数が配列内に1つも存在しない場合は、0 を返します。例えば、入力が [21, 4, 7] の場合、出力は 32 になります。これは次のような理由によるものです。21 の約数は 1, 3, 7, 21 の4つ → 条件を満たす4 の約数は 1, 2, 4 の3つ → 条件を満たさない7 の約数は 1, 7 の2つ → 条件を満たさないしたがって、答えは条件を満たす 21 の約数の総和である 32 となります。解法のアプローチこの問題を解く