之前在博客https://blog.csdn.net/hanzhen7541/article/details/99710954中我们讨论了一种单调栈的解法,复杂度是O(nlogn)。那么实际上还有一种解法,用的是动态规划+二分查找。
首先看一下题目:
小Q在周末的时候和他的小伙伴来到大城市逛街,一条步行街上有很多高楼,共有n座高楼排成一行。
小Q从第一栋一直走到了最后一栋,小Q从来没有看到过这么多高楼,所以他想知道他在每栋楼的位置处能看到多少栋楼呢?(当前面的楼的高度大于等于后面的楼时,后面的楼将被挡住)
输入描述:
输入第一行将包含一个数字n,表示楼的栋数,接下来的一行将包含n个数字wi(1<=i<=n),代表一栋楼的高度。
1<=n<=100000;
1<=wi<=100000;
输出描述:
输出一行,包含空格分隔的m个数字vi,分别代表小Q在第i栋楼的时候能看到的楼的数量。
对于这类最长的下降(上升)子序列问题,动态规划是一种非常好的办法。解题思路是:首先设dp1[i-1]是一个存放第i个位置往左看能看到多少高楼的数组(dp1[0]就是1,表示从1位置往左看一定能看到最左边这个楼)。dp3[i]维护了一个下降的队列,对于每一个height[i],都应该在dp3的某一个位置pos,这个位置pos是队列中第一个比height[i]小或者等于的位置,把它插入进去。
同时我们维护一个变量tmp,这个变量非常关键,表示的是每次比较从dp3[0]比较到dp[tmp]之间。为什么要维护这个变量呢?我们举个例子,假如说之前dp3维护的队列高度是8,5,3,1这样一个队列,假设下一个楼的高度是6,那么它将找到pos=1也就是高度是5的位置,将5替换成6. 同时,将tmp记录为pos也就是1的位置。那么对于下一个数字来说,假如是2,他显然不能在所有的8,6,3,1这个序列中比较,因为前一个数字5已经把3,1这两个楼的高度“挡住了”,所以这个tmp实际上维护了一个查找的范围,保证只能在0~tmp这些索引里面来找,从而起到忽略已经被挡住的楼的作用。
我们来看一下代码:
int main(){
int n;
cin >> n;
vector<int>x(n);
vector<int>dp1(n, 0);
vector<int>dp2(n, 0);
for (int i = 0; i<n; i++) cin >> x[i];
vector<int>dp3(n, 0);
int tmp = 0;
//dp1[i-1]表示从第i个位置向左看能看到的高楼的个数,tmp表示只看从0到tmp之间的楼,因为一个比较高的楼会挡住前面比较矮的楼
for (int i = 0; i<n; i++){
int pos = lower_bound(dp3.begin(), dp3.begin() + tmp + 1, x[i], greater<int>()) - dp3.begin();
/*如果x[i]比所有序列值都小,那么pos返回tmp+1,也就是下面if语句第一句,从物理意义上来说,直接把他接在下降序列的末尾就可以了*/
if (pos>tmp) tmp++;
/*如果在0~tmp里面能找到一个值,那么tmp就取成当前的pos值,对于后面的i来说,只需要查找0~tmp里面的值,tmp索引以后的较小值相当于被忽略了*/
else tmp = pos;
dp3[pos] = x[i];
dp1[i] = pos+1;
}
dp3.clear();
dp3.resize(n, 0);
tmp = 0;
for (int i = n - 1; i >= 0; i--){
int pos = lower_bound(dp3.begin(), dp3.begin() + tmp + 1, x[i], greater<int>()) - dp3.begin();
if (pos>tmp)tmp++;
else tmp = pos;
dp3[pos] = x[i];
dp2[i] = pos+1;
}
for (int i = 0; i<n; i++){
int ct = 1 + (i == 0 ? 0 : dp1[i - 1]) + (i == n - 1 ? 0 : dp2[i + 1]);
cout << ct << " ";
}
cout << endl;
system("pause");
return 0;
}
相关阅读:最长上升子序列:https://blog.csdn.net/hanzhen7541/article/details/99721688
upper_bound() 用法 :https://blog.csdn.net/hanzhen7541/article/details/99722948
另一种解法: https://blog.csdn.net/hanzhen7541/article/details/99710954
我觉得这道题很难想。自己很菜,还希望和大家多多讨论。