二分查找
二分查找,思想很简单,在很多书中都有介绍,如果查找的元素一定存在序列中,实现起来简单一些。但是有的时候元素并不存在,就要根据题目中的要求,去判断是去求上界还是去求下界。以下内容参考此博客,这个博客讲的很不错,参考了一下。以下所有的题目,都是递增序列。
HDU 4217 Data Structure? 题目大意就是让把第几大的元素找到,然后把这个元素删去,算出删去元素的和。这个题的一种解法是用树状数组记录,然后中间用到二分,这个时候因为getsum(i)存的是前i个数有有几个元素,所以第一个等于关键值的i,才是要求的结果。最后str是我们要求的结果。
关键代码:
1 while(str < end)//必须小于,小于等于会超时 2 { 3 mid = (str+end)/2; 4 midsum = getsum(mid);//树状数组的求和 5 if(midsum < a)//a是关键值 6 str = mid+1;
7 else
8 end = mid;//必须这么写
9 }
HDU 4151The Special Number 很早之前做的一个题了,这个二分写的更加纠结。。。暴力预处理出所有的结果,找寻第一个比a小的元素,感觉既不是求上界也不是求下界。这个题看的题解,二分写的很巧妙。key为最后的结果,而且必须这样写,其实我也不太懂为什么这样写。。。
1 while(str <= end)//必须这么写。。。不加等号会WA。。 2 { 3 mid = str + (end - str)/2; 4 if(p[mid] < a) 5 { 6 key = mid;//key记录第一个比a小的值 7 str = mid+1; 8 } 9 else 10 { 11 end = mid-1;//必须-1,不然也会超时。。 12 } 13 }
今天又看这个题,这就是求上界啊,只要最后讨论下,是否与关键值相等即可。
1 while(str < end) 2 { 3 mid = (str + end + 1)/2; 4 if(p[mid] > a) 5 { 6 end = mid - 1; 7 } 8 else 9 { 10 str = mid; 11 } 12 } 13 if(p[end] == a) 14 printf("%d\n",end - 1); 15 else 16 printf("%d\n",end);
二分求上界最后一次出现的位置,如果不存在,就是左边第一个小于a的元素。end是取得的结果。
1 while(str < end) 2 { 3 mid = (str + end + 1)/2;//注意。。。+1 4 if(mid > a) 5 { 6 end = mid - 1;//注意。。 7 } 8 else 9 { 10 str = mid; 11 } 12 }
二分求下界。str为最后的结果。第一个出现的和a相等的元素,如果不存在就是右边,第一个比a大的元素。
1 while(str < end) 2 { 3 mid = (str + end)/2; 4 if(p[mid] < a) 5 { 6 str = mid + 1; 7 } 8 else 9 { 10 end = mid; 11 } 12 }