C++で解く「次のより大きい要素 III」(Next Greater Element III)の実装方法
32ビットの正の整数 n が与えられたとき、n とまったく同じ数字の並びを持ち、かつ n よりも大きい値となる最小の32ビット整数を求めます。そのような整数が存在しない場合は -1 を返します。
例えば、入力が 213 の場合、同じ数字を使って作れるより大きい数のうち最小のものは 231 なので、答えは 231 になります。
解法のアプローチ
この問題は、いわゆる「次の順列(next permutation)」を求めるアルゴリズムと同じ考え方で解くことができます。手順は以下の通りです。
s:=nを文字列に変換したもの、sz:=sの長さ、ok:= false と初期化するiをsz - 2から0まで降順に走査する。もしs[i] < s[i + 1]が成り立てば、ok:= true としてループを抜けるokが false のままなら、桁がすべて降順に並んでいる(これより大きい並べ替えが存在しない)ため、-1を返すsmallest:=i、curr:=i + 1とするjをi + 1からsz - 1まで走査し、s[j] > s[smallest]かつs[j] <= s[curr]を満たすたびにcurr:=jと更新するs[smallest]とs[curr]を入れ替えるaux:=sのインデックスsmallest + 1以降の部分文字列とし、auxを反転するret:=sの先頭からsmallestまでの部分文字列にauxを連結したものとするretが32ビット正整数の範囲を超えていれば-1を、そうでなければretを返す
このアルゴリズムのポイントは、右端から見て最初に「左の数字が右の数字より小さい」位置を見つけ、その位置の数字を、右側に残った数字の中で「その数字より大きい最小の数字」と入れ替え、残りを昇順に並べ直す(反転操作で実現できる)ことです。これにより、桁数を d とすると O(d) の計算量で次に大きい数を効率的に求められます。
実装例
理解を深めるために、以下の C++ 実装を見てみましょう。
Example
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
int nextGreaterElement(int n) {
string s = to_string(n);
int sz = s.size();
int i;
bool ok = false;
for(i = sz - 2; i >= 0; i--){
if(s[i] < s[i + 1]) {
ok = true;
break;
}
}
if(!ok) return -1;
int smallest = i;
int curr = i + 1;
for(int j = i + 1; j < sz; j++){
if(s[j] > s[smallest] && s[j] <= s[curr]){
curr = j;
}
}
swap(s[smallest], s[curr]);
string aux = s.substr(smallest + 1);
reverse(aux.begin(), aux.end());
string ret = s.substr(0, smallest + 1) + aux;
return stol(ret) > INT_MAX ? -1 : stol(ret);
}
};
main(){
Solution ob;
cout << (ob.nextGreaterElement(213));
}
入力
213
出力
231
-
C++で解く「次に大きい要素 II」:循環配列のNext Greater Element問題
問題概要循環配列(最後の要素の次は配列の最初の要素に戻る配列)が与えられたとき、各要素に対して「次に大きい数(Next Greater Number)」を求めて表示することを考えます。ある数 x の次に大きい数とは、走査順において x より後で最初に現れる、x より大きな値のことです。このとき配列は循環しているため、末尾を超えたら先頭に戻って探索を続けることができます。もし次に大きい数が存在しない場合は -1 を返します。例えば、入力が [1, 2, 1, 3, 2, 1] の場合、出力は [2, 3, 3, -1, 3, 2] となります。最初の「1」の次に大きい数は「2」「2」の次に大きい
-
C++で配列の「直前のより大きい要素」を効率的に求める方法
問題の概要この問題では、整数の配列が与えられます。配列の各要素について、その要素より前方(左側)に位置する要素の中で最大の値を見つけて出力します。該当する要素が存在しない場合は -1 を出力します。入出力例入力: {6, 2, 7, 1, 5, 3} 出力: -1, 6, -1, 7, 7, 7この例では、最初の要素「6」の前方には要素が存在しないため -1。2番目の要素「2」の前方にあるのは「6」だけなので 6。3番目の要素「7」の前方に「7」より大きい要素はないため -1。4番目の要素「1」の前方には「7」があるので 7。以降も同様に判定していきます。解法1: 二重ループによる単純なアプロ