二分搜索模板

 1 int bs1(int x,int y,int t) {  //二分求上界 
 2     while(x <= y) {
 3         int mid = x + (y - x) / 2;
 4         if(num[mid] <= t) x = mid + 1;
 5         else y = mid - 1;
 6     }
 7     return x;
 8 }
 9 int bs2(int x,int y,int t) { //二分求下界 
10     while(x <= y) {
11         int mid = x + (y - x) / 2;
12         if(num[mid] >= t) x = mid + 1;
13         else y = mid - 1;
14     }
15     return x;
16 }
View Code

 与之相关的有nlogn的最长上升子序列,最长下降子序列的算法

http://blog.csdn.net/wall_f/article/details/8295812

 

另外大致讲下nlogn求最长上升子序列的思想。

其实跟背包问题里把二维数组降维的思想特别像。

举个栗子:

1 2 3  4  5 6

1 2 4 10 3 5

i先从1循环到4

dp[1]=1; dp[2]=2; dp[3]=4; dp[4]=10; //dp数组的值代表最长上升子序列的长度,此时len=4

当i循环到5的时候,发现dp[len]>nu[5],此时如果按照我们最直接思想是从前往后遍历一遍dp数组,找到第一个大于nu[5]的数,列出第二种情况。

即:

一: 1 2 4 10

二: 1 2 3

然后接着遍历,但要对着dp[m][n]数组进行遍历了。这个时候我们可以联想一下01背包问题降维的思路,也就是从后往前遍历dp数组,使得其无后效性。那这个其实也是一样的,我们可以发现dp[2][n]根本没有存在的必要,只需要把dp[1][3]=3即可,这样dp[1][n]d 最终的结果len不会改变(因为len是否增加,只与dp[1][len]有关),也满足了我们只遍历一个数组就可以考虑到这两种情况的需求。

以此类推,最后其实就是遍历nu数组

1.如果nu[i]>dp[len],dp[++len]=nu[i];

2.否则,二分遍历dp数组,找到第一个大于nu[i]的数,用nu[i]取代它,更新数组。

这个是我的理解,下面还有另一种理解方法,感觉讲得也很好,分享给大家。

http://www.cnblogs.com/itlqs/p/5743114.html

posted @ 2017-09-30 23:17  euzmin  阅读(216)  评论(0编辑  收藏  举报