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 }
与之相关的有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