新しいタイポグラフィのテーマに変更されました、ハハ、どう思いますか?
注意:一部のレコーディングの友人は、毎日記事が表示されないことが多いと述べています。現在、公式アカウントは送信時間に応じて推奨しなくなりましたが、一部のルールに従って順序が狂っているため、「コードランダムレコード」に注意を払っていて、記事を表示できなかった可能性があります。「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の割り当てを開始する場所をマークするなど、いくつかのスキルも必要です。
アルゴリズムを段階的に学び、「コードランダムレコード」を探してください!