貪欲なアルゴリズム:単調に増加する数

新しいタイポグラフィのテーマに変更されました、ハハ、どう思いますか?

注意:一部のレコーディングの友人は、毎日記事が表示されないことが多いと述べています。現在、公式アカウントは送信時間に応じて推奨しなくなりましたが、一部のルールに従って順序が狂っているため、「コードランダムレコード」に注意を払っていて、記事を表示できなかった可能性があります。「CodeCaprice」のスターを設定することをお勧めします。スターを設定すると、毎日の投稿時間に応じてプッシュされます。Carlは毎日8:35に定期的に送信します。

738.単調に増加する数値
非負の整数Nが与えられた場合、N以下の最大の整数を見つけます。この整数は、各桁の数値が単調に増加していることを満たす必要があります。

(隣接する各桁の数値xとyがx <= yを満たす場合にのみ、この整数を単調に増加すると呼びます。)

例1:
入力:N = 10
出力:9

例2:
入力:N = 1234
出力:1234

例3:
入力:N = 332
出力:299

説明:Nは[0、10 ^ 9]の範囲の整数です。


暴力的な解決策の考え方
は非常に単純なので、最初に考えるのは暴力的な解決策です。暴力の波について言及しましょう。結果は当然のことながら残業です。

コードは次のように表示されます。


class Solution {
private:
    bool checkNum(int num) {
        int max = 10;
        while (num) {
            int t = num % 10;
            if (max >= t) max = t;
            else return false;
            num = num / 10;
        }
        return true;
    }
public:
    int monotoneIncreasingDigits(int N) {
        for (int i = N; i > 0; i--) {
            if (checkNum(i)) return i;
        }
        return 0;
    }
};
  • 時間の複雑さ:O(n * m)mはnの数の長さです
  • スペースの複雑さ:O(1)
    貪欲なアルゴリズムの
    問題では、N以下の単調に増加する最大の整数が必要になるため、例として2桁の数値を取り上げます。

例:98、strNum [i-1]> strNum [i]が発生すると(単調に増加しない)、最初にstrNum [i-1]-が必要になり、次にstrNum [i]が9になるため、この整数は次のようになります。 89は、98未満の単調に増加する最大の整数です。

これをはっきりと考えれば、この質問は扱いやすくなります。

ローカル最適:strNum [i-1]> strNum [i]の場合、strNum [i-1]-、次にstrNum [i]を9にして、これら2つのビットが単調に増加する最大の整数になるようにします。 。

グローバル最適:N以下の単調に増加する最大の整数を取得します。

ただし、ここではローカル最適値はグローバル最適値から導出され、他の条件、つまりトラバーサル順序とビットが9に変更されるマークが必要です。

前から後ろにトラバースするのですか、それとも後ろから前にトラバースするのですか?

前から後ろにトラバースする場合、strNum [i-1]> strNum [i]が発生した場合、strNum [i-1]に1を減算させますが、strNum [i-1]を1減算すると、strNumよりも小さくなる場合があります。 [i-2]。

これは少し抽象的です。たとえば、数値:332です。前から後ろにトラバースすると、329になります。このとき、2は最初の3よりも小さく、実際の結果は299になります。

したがって、前から後ろにトラバースすると、トラバースされた結果が変わります。

次に、後ろから前にトラバースすると、最後の比較の結果を再利用できます。後ろから前へのトラバースの332の値は、332-> 329-> 299に変更されます。

トラバーサルシーケンスを決定した後、この時点でローカル最適値をグローバルから導出できます。反例が見つからない場合は、貪欲に試してください。

C ++コードは次のとおりです。


class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};
  • 時間の複雑さ:O(n)nは数値の長さです
  • スペースの複雑さ:O(n)には文字列が必要であり、文字列操作に変換する方が便利です。この質問
    を要約すると、
    98などの明確な例を考えてみてください。strNum[i-1]> strNum [i]が発生すると(単調に増加しない) )、最初にstrNum [i-1]から1を減算し、strNum [i]に9を割り当てて、整数が89になるようにします。あなたは自然に対応する貪欲な解決策を考えることができます。

貪欲を考えると、トラバースの順序も考慮する必要があります。後ろから前にトラバースすることによってのみ、最後の比較の結果を再利用できます。

最終的なコードを実装するときは、フラグを使用して9の割り当てを開始する場所をマークするなど、いくつかのスキルも必要です。

アルゴリズムを段階的に学び、「コードランダムレコード」を探してください!

おすすめ

転載: blog.51cto.com/15069438/2576225
おすすめ