描述:給定一個序列,求出序列每一個位置在左側距離其最近的,且比起小的數,若是不存在則返回-1,存在則返回其值, 最後輸出該結果。
解析: 首先考慮對該題目的樸素解(暴力解法),挖掘一些性質,把求解空間進一步縮小,從而下降問題的求解時間複雜度。 1. 暴力作法 雙重循環:第一重循環,遍歷序列上全部的位置i; 第二重循環,從第一重循環的位置i開始,向左遍歷,直到找到第一個比位置i處的值,不然輸出-1,表示不存在這樣的小值; 僞碼以下: for i = 0; i < n; i++ for j = i- 1; j >= 0; j-- if (a[i] > a[j]) { cout << a[j] <<endl; break; } cout << -1 << endl; 2.分析特性 能夠觀察,當咱們經過一些數據結構,能夠保留以前遍歷過的全部的元素,對於給定位置i, 那麼假設在i的左側存在兩個位置j,k,知足 a[j] >= a[k] (j < k),由於是須要找左側最近,因此這時選擇k位置比j位置更優,對於位置i,位置k更優,所以能夠捨去位置j。 由於上面其實是逆序的狀況,要刪除這種逆序狀況,這樣獲得的序列是嚴格遞增的。由於咱們在比較時,老是要比較左側最近的點,所以須要使用棧的數據結構來 使用。 3.代碼實現 stack st; int a[N]; for (int i = 0; i < n; i++) { //對於位置i,須要考察期左側的棧序列; while (!st.empty() && st.top() >= a[i]) { //棧非空,且比棧頂元素小,說明其能夠取代棧頂成爲更優解; st.pop(); } //此處要麼棧爲空,或者當前元素比棧頂大; if (!st.empty()) { //此時棧非空,那麼棧頂就是其左側比當前值還小的元素; cout << st.top() << endl; } else { //棧爲空,說明左側沒有符合的值了,這個時候輸出特殊狀況處理; cout << -1 <<endl; } //將當前元素添加進去,由於在當前元素以前已經保持了嚴格遞增,將當前元素添加進去後,單調性仍是保持不變 //由於前面的if語句已經保證了,從而能夠保證該性質能夠求解。 st.push(a[i]); }
#include <iostream> #include <algorithm> using namespace std; const int N = 100010; //這裏採用的是數組模擬棧的方式,徹底可用STL的方式來寫,只不過會增長一些運行時間; int n; int stk[N], tt; int main() { cin >> n; for (int i = 0; i < n; i++) { int x; cin >> x; while (tt && stk[tt] >= x) tt--; if (tt) cout << stk[tt] <<" "; else cout << -1 <<" "; stk[++tt] = x; } cout <<endl; return 0; }
相似的,還有尋找左側最近且最大的,右側最近最小/最大的問題。ios