件名のソース:https://leetcode-cn.com/problems/next-greater-element-ii/
タイトル説明
ループ配列(最後の要素の次の要素は配列の最初の要素)が与えられた場合、各要素の次に大きい要素を出力します。数値xの次に大きい要素は、配列走査順序です。この数値の後の最初の数値はそれよりも大きいため、ループ内で次に大きい数値を検索する必要があります。存在しない場合は-1を出力します。
例1:
入力:[1,2,1]
出力:[2、-1,2]
説明:最初の1の次に大きい数は2です;
数2は次に大きい数を見つけることができません;
次に大きい数2番目の1はループで検索する必要があり、結果も2になります。
注:入力配列の長さは10,000を超えません。
一般的なアイデア
- 出力要素はすべて現在の要素の次に大きい要素であり、配列は周期的にトラバースできます。つまり、条件を満たす要素が前から後ろに見つからない場合、トラバーサルは配列の先頭から開始されます。現在の要素の前の要素に移動します。この場合、見つからない場合は-1を出力し、配列を返します。
暴力のサイクル
- hash_mapを維持できます。現在の要素にアクセスするときは、最初にハッシュマップでその要素を探し、ハッシュマップのキーと同じ要素値がすでに存在するかどうかを確認します。存在する場合は、値の値で[0]を比較します添え字ビットとしての配列。現在の添え字がインデックス添え字よりも小さい場合は、この添え字をans配列に直接配置できます。それ以外の場合は、現在の要素から逆方向にトラバースします。見つからない場合は、からトラバースします。配列の開始から現在の要素の前まで、このサイクル
class Solution {
public:
vector<int> ans;
vector<int> nextGreaterElements(vector<int>& nums) {
// index value
unordered_map<int, vector<int>> mmap;
ans.clear();
bool flag = false;
int len = nums.size();
for(int i = 0 ; i < len ; ++i){
auto it = mmap.find(nums[i]);
if(it != mmap.end()){
if((it->second)[0] > i)
ans.push_back((it->second)[1]);
else{
flag = FindNextBigNum(mmap, i + 1, len, nums, nums[i]);
if(!flag)
flag = FindNextBigNum(mmap, 0, i, nums, nums[i]);
if(!flag){
ans.push_back(-1);
mmap[nums[i]] = {
2 * len, -1};
}
}
}else{
flag = FindNextBigNum(mmap, i + 1, len, nums, nums[i]);
if(!flag){
for(int j = i + 1 ; j < i + len ; ++j){
if(nums[j % len] > nums[i]){
mmap[nums[i]] = {
j, nums[j % len]};
ans.push_back(nums[j % len]);
flag = true;
break;
}
}
if(!flag){
mmap[nums[i]] = {
2 * len, -1};
ans.push_back(-1);
}
}
}
}
return ans;
}
bool FindNextBigNum(unordered_map<int, vector<int>>& mmap, int left, int right, vector<int>& nums, int target)
{
int len = nums.size();
for(int j = left;j < right; ++j){
if(nums[j % len] > target){
mmap[target] = {
j, nums[j % len]};
ans.push_back(nums[j % len]);
return true;
}
}
return false;
}
};
複雑さの分析
- 時間計算量:O(n ^ 2)。最悪の場合、配列は逆の順序[6,5,4,3,2,1]であり、各要素を最後までトラバースしてから最初までトラバースする必要があります
- スペースの複雑さ:O(n)。ハッシュ配列を維持します
単調なスタック
- 上記の解の時間計算量が大きすぎる場合は、問題のより良い解決策を率先して考えることができます。[現在の値よりも大きい/小さい値を見つける]のタイプの場合、単調を使用できます。上記の解がO(n)である理由は、現在の値よりも大きい次の要素を[積極的に]探しているため、考えを変えることができます。まだ受け取っていない添え字を一時的に保存します。 [パッシブ]検索を実現するためにスタックに回答する
- スタック内の要素のインデックスは、常に更新されていない回答のインデックスです。
- [現在トラバースされた添え字がスタックに格納されるたびに、現在の添え字がスタックに格納される前に、現在の値がスタック内の位置に対する回答として使用できるかどうかを確認します(つまり、「次の」になりますより大きな要素」)、可能であれば、スタックに添え字をポップします](他の人の説明の元の単語を削除します)https://leetcode-cn.com/problems/next-greater-element-ii/solution/cong-po -su-jie-fa-de-jiao-du-qu-li-jie-d-trht /
class Solution {
public:
vector<int> nextGreaterElements(vector<int>& nums) {
int len = nums.size();
// 默认为-1,如果有元素没出栈的话
vector<int> ans(len, -1);
stack<int> queue;
for(int i = 0 ; i < 2 * len - 1 ; ++i){
while(!queue.empty() && nums[i % len] > nums[queue.top()]){
ans[queue.top()] = nums[i % len];
queue.pop();
}
queue.push(i % len);
}
return ans;
}
};
複雑さの分析
- 時間計算量:O(n)。
- スペースの複雑さ:O(n)。スタック内の要素の数は、最大で配列と同じ長さです