この手のスタックの問題はもうすっかり常識と化した!
問題概要
ビル がこの順に並んでいる。ビル の高さは である。
各 に対して、ビル の間にビル より高いものがないような () の個数を求めよ。
制約
考えたこと
いかにもスタックを使いそうな匂いがする問題だ。
たとえば について、後ろから考えてみよう。次のようになる。
自分より後ろにある、条件を満たす についての のリスト | 備考 | ||
---|---|---|---|
7 | 6 | {} | そもそも後ろのビルがない |
6 | 2 | {6} | |
5 | 9 | {2, 6} | |
4 | 5 | {9} | 高さ 9 のビルが、高さ 2, 6 のビルよりも高いので、高さ 2, 6 のビルは見えなくなる |
3 | 1 | {5, 9} | |
2 | 4 | {1, 5, 9} | |
1 | 1 | { 4, 5, 9 } | 高さ 4 より低い高さ 1 のビルは見えなくなるが、高さ 5, 9 のビルは依然として見える |
0 | 3 | {1, 4, 5, 9} |
このように実験してみると、毎回次の処理をしていけばよいことがわかる。
ビル を追加するとき、前回求めた建物リストについて、 よりも低い建物を削除していき、新たにビル を挿入する
この挙動はスタックとなっている。ただし、通常スタックは末尾に挿入して末尾から pop する。それに対して今回は、先頭に挿入して先頭から pop するような感じになっている。しかしながら、建物リスト全体を reverse
すれば、末尾に挿入して末尾から pop するような通常のスタックになる。
スタックを用いて実装すれば全体の計算量は となる。
コード
ここでは vector<int>
型を用いてスタックを実現した。
#include <bits/stdc++.h> using namespace std; int main() { int N; cin >> N; vector<int> H(N); for (int i = 0; i < N; i++) cin >> H[i]; vector<int> st, res; for (int i = N-1; i >= 0; i--) { res.push_back(st.size()); while (!st.empty() && st.back() < H[i]) st.pop_back(); st.push_back(H[i]); } reverse(res.begin(), res.end()); for (int i = 0; i < N; i++) cout << res[i] << " "; cout << endl; }