描述:给定一个序列,求出序列每一个位置在左侧距离其最近的,且比起小的数,若是不存在则返回-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