二分查找问题全集_第1页
二分查找问题全集_第2页
二分查找问题全集_第3页
二分查找问题全集_第4页
二分查找问题全集_第5页
已阅读5页,还剩8页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、二分查找问题全集1,原始二分查找题目:给定一个有序(非降序)数组A,求任意一个i使得Ai等于target,不存在则返回-1例如:2,4,6,8,9找(4) 位置11.1 递归版cpp view plain copyprint?1. int bSearch(int a, int low, int high, int target)  2.     if(low > high)  3.   &#

2、160;     return -1;  4.     int mid = (low + high)/2;  5.     if(target<amid)  6.         return bSearch(a,low,mid-1,target);&#

3、160; 7.     else if(target>amid)  8.         return bSearch(a,mid+1,high,target);  9.     /if(target = amid)  10.     return mid; &#

4、160;11.   int bSearch(int a, int low, int high, int target)if(low > high)return -1;int mid = (low + high)/2;if(target<amid)return bSearch(a,low,mid-1,target);else if(target>amid)return bSearch(a,mid+1,high,target);/if(target = amid)return mid;1.2 迭代版cpp view plain copyprint?1. int

5、 search(int A, int n, int target)  2.   3.     int low = 0, high = n-1;  4.     while(low <= high)  5.       6.  

6、;       / 注意:若使用(low+high)/2求中间位置容易溢出  7.         int mid = low+(high-low)>>1);   8.         if(Amid = target)  9.

7、             return mid;  10.         else if(Amid < target)  11.             low = mid

8、+1;  12.         else / Amid > target  13.             high = mid-1;  14.       15.     

9、;return -1;  16.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high)/ 注意:若使用(low+high)/2求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = target)return mid;else if(Amid < target)low = mid+1;else / Amid > targethigh = mid-1;return -1

10、;1.3 返回插入位置给定一个有序(非降序)数组A,若target在数组中出现,返回位置,若不存在,返回它应该插入的位置。cpp view plain copyprint?1. int search(int A, int n, int target)  2.   3.     int low = 0, high = n-1;  4.    

11、0;while(low <= high)  5.       6.         / 注意:若使用(low+high)/2求中间位置容易溢出  7.         int mid = low+(high-low)>>1);   

12、8.         if(Amid = target)  9.             return mid;  10.         else if(Amid < target)  11.

13、             low = mid+1;  12.         else / Amid > target  13.             high 

14、= mid-1;  14.       15.     return -(low+1);  16.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high)/ 注意:若使用(low+high)/2求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = ta

15、rget)return mid;else if(Amid < target)low = mid+1;else / Amid > targethigh = mid-1;return -(low+1);之所以返回-(low+1)而不是直接返回-low是因为low可能为0,如果直接返回-low就无法判断是正常返回位置0还是查找不成功返回的0。 2,含重复元素,求=target的最小一个问题:给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得Ai等于target,不存在则返回-1例如:A2,4,6,8,8,8,9求8得最小位置3cpp view plain copyprint?1

16、. int search(int A, int n, int target)  2.   3.     int low = 0, high = n-1;  4.     while(low <= high)         

17、          5.       6.         / 注意:若使用(low+high)/2求中间位置容易溢出  7.         int mid = low+(high-low)>>1);

18、60;  8.         if(Amid = target)  9.           10.             if(mid > 0 && Amid-1 

19、;= target)  11.                 high = mid-1;             12.            &#

20、160;else   13.                 return mid;  14.           15.         else if(Amid <

21、60;target)  16.             low = mid+1;               17.         else / Amid > t

22、arget  18.             high = mid-1;             19.       20.     return -(low+1);   

23、; 21.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high) / 注意:若使用(low+high)/2求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = target)if(mid > 0 && Amid-1 = target)high = mid-1; else return mid;else if(Amid < target)low = mid+1; else

24、 / Amid > targethigh = mid-1; return -(low+1); 3,含重复元素,求=target的最大一个问题:给定一个有序(非降序)数组A,可含有重复元素,求最大的i使得Ai等于target,不存在则返回-1例如:A2,4,6,8,8,8,9求8得最大位置5cpp view plain copyprint?1. int search(int A, int n, int target)  2.   3.     int&

25、#160;low = 0, high = n-1;  4.     while(low <= high)                   5.       6.     

26、    / 注意:若使用(low+high)/2求中间位置容易溢出  7.         int mid = low+(high-low)>>1);   8.         if(Amid = target)  9.    

27、       10.             if(mid < n-1 && Amid+1 = target)  11.                

28、60;low = mid+1;             12.             else   13.                 

29、;return mid;  14.           15.         else if(Amid < target)  16.             low = mid+1; 

30、;              17.         else / Amid > target  18.             high = mid-1; 

31、60;           19.       20.     return -(low+1);    21.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high) / 注意:若使用(low+high)/2

32、求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = target)if(mid < n-1 && Amid+1 = target)low = mid+1; else return mid;else if(Amid < target)low = mid+1; else / Amid > targethigh = mid-1; return -(low+1); 4,含重复元素,求<target的最大一个问题:给定一个有序(非降序)数组A,可含有重复元素,求最大的i使得Ai小于target,不存在则返回

33、-1例如:A2,4,6,8,8,8,9求9得最大位置5问题转化:含重复元素,求2【=target的最小一个】的前一个。cpp view plain copyprint?1. int search(int A, int n, int target)  2.   3.     int low = 0, high = n-1;  4.     

34、while(low <= high)                   5.       6.         / 注意:若使用(low+high)/2求中间位置容易溢出  7.   

35、0;     int mid = low+(high-low)>>1);   8.         if(Amid = target)  9.           10.        &

36、#160;    if(mid > 0 && Amid-1 = target)  11.                 high = mid-1;           

37、;  12.             else   13.                 return (mid=0)?-1:mid-1;  14.        &#

38、160;  15.         else if(Amid < target)  16.             low = mid+1;             

39、0; 17.         else / Amid > target  18.             high = mid-1;             19. 

40、0;     20.     return -(low+1);    21.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high) / 注意:若使用(low+high)/2求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = target)if(mid > 0 &

41、amp;& Amid-1 = target)high = mid-1; else return (mid=0)?-1:mid-1;else if(Amid < target)low = mid+1; else / Amid > targethigh = mid-1; return -(low+1); 5,含重复元素,求>target的最小一个问题:给定一个有序(非降序)数组A,可含有重复元素,求最小的i使得Ai大于target,不存在则返回-1例如:A2,4,6,8,8,8,9求6的最小位置3问题转化:含重复元素,求3【=target的最大一个】的后一个。cpp vi

42、ew plain copyprint?1. int search(int A, int n, int target)  2.   3.     int low = 0, high = n-1;  4.     while(low <= high)     

43、0;             5.       6.         / 注意:若使用(low+high)/2求中间位置容易溢出  7.         int mid = low+(hig

44、h-low)>>1);   8.         if(Amid = target)  9.           10.             if(mid < n-1 &

45、& Amid+1 = target)  11.                 low = mid+1;             12.         

46、;    else   13.                 return (mid=n-1)?-n:mid+1;  14.           15.        

47、 else if(Amid < target)  16.             low = mid+1;               17.         el

48、se / Amid > target  18.             high = mid-1;             19.       20.     re

49、turn -(low+1);    21.   int search(int A, int n, int target)int low = 0, high = n-1;while(low <= high) / 注意:若使用(low+high)/2求中间位置容易溢出int mid = low+(high-low)>>1); if(Amid = target)if(mid < n-1 && Amid+1 = target)low = mid+1; else return (mid=n-1)

50、?-n:mid+1;else if(Amid < target)low = mid+1; else / Amid > targethigh = mid-1; return -(low+1); 6,含重复元素,求=target的出现次数问题:给定一个有序(非降序)数组A,可含有重复元素,求target在数组中出现的次数。例如:A2,4,6,8,8,8,9求8的出现次数3求出第一次出现位置和最后一次出现位置。由于前面都已实现,这里不多解释。请参考实现代码与注释cpp view plain copyprint?1. int count(int A, int&

51、#160;n, int target)  2.   3.     int firstPos = searchFirstPos(A, n, target); / 第一次出现位置  4.     if(firstPos = -1)  5.         

52、;return 0;  6.     int lastPos = searchLastPos(A, n, target);  / 最后一次出现位置  7.     return lastPos-firstPos+1;  / 出现次数  8.   int count(int A, int n, int targ

53、et)int firstPos = searchFirstPos(A, n, target); / 第一次出现位置if(firstPos = -1)return 0;int lastPos = searchLastPos(A, n, target); / 最后一次出现位置return lastPos-firstPos+1; / 出现次数7,含重复元素,求绝对值最小的元素问题:给定一个有序(非降序)数组A,可含有重复元素,求绝对值最小的元素的位置例如:A-4,-2,-1,2,3,8,9求结果为2cpp view plain copyprint?1. int searchMinAbs(i

54、nt A, int n)  2.   3.     int low = 0, high = n-1;  4.     while(low < high)  5.       6.        

55、 int mid = low+(high-low)>>1);  7.         if(Amid < 0)  8.             low = mid+1;  9.      &#

56、160;  else / Amid >= 0  10.             high = mid;  11.       12.     /* 循环结束时,如果low != n-1,Alow >=

57、0;0,如果low>0,Alow-1 < 0 */  13.     if(low > 0 && abs(Alow-1) < abs(Alow)  14.         return low-1;  15.     else &

58、#160;16.         return low;  17.   int searchMinAbs(int A, int n)int low = 0, high = n-1;while(low < high)int mid = low+(high-low)>>1);if(Amid < 0)low = mid+1;else / Amid >= 0high = mid;/* 循环结束时,如果low != n-1,Alow >=

59、0,如果low>0,Alow-1 < 0 */if(low > 0 && abs(Alow-1) < abs(Alow)return low-1;elsereturn low;8,问题:给定一个有序(非降序)数组A和一个有序(非降序)数组B,可含有重复元素,求两个数组合并结果中的第k(k>=0)个数字。这个题目出现了两个数组,有序的,不管怎样我们就应该首先考虑二分查找是否可行。若使用顺序查找,时间复杂度最低为O(k),就是类似归并排序中的归并过程。使用用二分查找时间复杂度为O(logM+logN)。二分查找的具体实现过程请参考实现代码与注释。cpp

60、 view plain copyprint?1. int findKthIn2SortedArrays(int A, int m, int B, int n, int k)  2.   3.     if(m <= 0) / 数组A中没有元素,直接在B中找第k个元素  4.       

61、60; return Bk;  5.     if(n <= 0) / 数组B中没有元素,直接在A中找第k个元素  6.         return Ak;  7.     int i = (m-1)>>1; / 数组A的中间位置 

62、; 8.     int j = (n-1)>>1; / 数组B的中间位置  9.     if(Ai <= Bj)  / 数组A的中间元素小于等于数组B的中间元素  10.       11.         

63、/* 12.         设x为数组A和数组B中小于Bj的元素数目,则i+1+j+1小于等于x, 13.         因为Ai+1到Am-1中还可能存在小于等于Bj的元素; 14.         如果k小于i+1+j+1,那么要查找的第k个元素肯定小于等于Bj, 15.    &

64、#160;    因为x大于等于i+1+j+1;既然第k个元素小于等于Bj,那么只 16.         需要在A0Am-1和B0Bj中查找第k个元素即可,递归调用下去。 17.         */  18.         if(k < i+1+j

65、+1)  19.           20.             if(j > 0)  21.                 return 

66、;findKthIn2SortedArrays(A, m, B, j+1, k);  22.             else / j = 0时特殊处理,防止死循环  23.               24. 

67、0;               if(k = 0)  25.                     return min(A0, B0);  26.  &#

68、160;              if(k = m)  27.                     return max(Am-1, B0);  28.  

69、0;              return Ak < B0 ? Ak : max(Ak-1, B0);  29.               30.      &

70、#160;    31.         /* 32.         设y为数组A和数组B中小于于等于Ai的元素数目,则i+1+j+1大于等于y; 33.         如果k大于等于i+1+j+1,那么要查找到第k个元素肯定大于Ai,因为 34.    

71、     i+1+j+1大于等于y;既然第k个元素大于Ai,那么只需要在Ai+1Am-1 35.         和B0Bn-1中查找第k-i-1个元素,递归调用下去。 36.         */  37.         else  38. &#

72、160;           return findKthIn2SortedArrays(A+i+1, m-i-1, B, n, k-i-1);  39.        40.     / 如果数组A的中间元素大于数组B的中间元素,那么交换数组A和B,重新调用即可  41. &#

73、160;   else  42.         return findKthIn2SortedArrays(B, n, A, m, k);  43.   int findKthIn2SortedArrays(int A, int m, int B, int n, int k)if(m <= 0) / 数组A中没有元素,直接在B中找第k个元素return Bk;if(n

74、<= 0) / 数组B中没有元素,直接在A中找第k个元素return Ak;int i = (m-1)>>1; / 数组A的中间位置int j = (n-1)>>1; / 数组B的中间位置if(Ai <= Bj) / 数组A的中间元素小于等于数组B的中间元素/*设x为数组A和数组B中小于Bj的元素数目,则i+1+j+1小于等于x,因为Ai+1到Am-1中还可能存在小于等于Bj的元素;如果k小于i+1+j+1,那么要查找的第k个元素肯定小于等于Bj,因为x大于等于i+1+j+1;既然第k个元素小于等于Bj,那么只需要在A0Am-1和B0Bj中查找第k个元素即可

75、,递归调用下去。*/if(k < i+1+j+1)if(j > 0)return findKthIn2SortedArrays(A, m, B, j+1, k);else / j = 0时特殊处理,防止死循环if(k = 0)return min(A0, B0);if(k = m)return max(Am-1, B0);return Ak < B0 ? Ak : max(Ak-1, B0);/*设y为数组A和数组B中小于于等于Ai的元素数目,则i+1+j+1大于等于y;如果k大于等于i+1+j+1,那么要查找到第k个元素肯定大于Ai,因为i+1+j+1大于等于y;既然第k个

76、元素大于Ai,那么只需要在Ai+1Am-1和B0Bn-1中查找第k-i-1个元素,递归调用下去。*/elsereturn findKthIn2SortedArrays(A+i+1, m-i-1, B, n, k-i-1); / 如果数组A的中间元素大于数组B的中间元素,那么交换数组A和B,重新调用即可elsereturn findKthIn2SortedArrays(B, n, A, m, k);9问题:一个有序(升序)数组,没有重复元素,在某一个位置发生了旋转后,求target在变化后的数组中出现的位置,不存在则返回-1如 0 1 2 4 5 6 7 可能变成 4 5 6 7 0 1 2我们

77、先比较中间元素是否是目标值,如果是返回位置。如果不是,我们就应该想办法将搜索区间减少一半。因为存在旋转变化,所以我们要多做一些判断。我们知道因为只有一次旋转变化,所以中间元素两边的子数组肯定有一个是有序的,那么我们可以判断target是不是在这个有序的子数组中,从而决定是搜索这个子数组还是搜索另一个子数组。具体请参考实现代码与注释。cpp view plain copyprint?1. int searchInRotatedArray(int A, int n, int target)   2. 

78、0; 3.     int low = 0, high = n-1;  4.     while(low <= high)  5.       6.         int mid = low+(high-low)

79、>>1);  7.         if(Amid = target)   8.             return mid;  9.         if(Amid >= Alo

80、w)   10.           11.             / low  mid 是升序的  12.             if(target &g

81、t;= Alow && target < Amid)  13.                 high = mid-1;  14.             else  

82、;15.                 low = mid+1;  16.           17.         else  18.      

83、;     19.             / mid  high 是升序的  20.             if(target > Amid && target <=&

84、#160;Ahigh)  21.                 low = mid+1;  22.             else  23.         

85、;        high = mid-1;  24.           25.       26.     return -1;  27.   int searchInRotatedArray(int A, int n, in

86、t target) int low = 0, high = n-1;while(low <= high)int mid = low+(high-low)>>1);if(Amid = target) return mid;if(Amid >= Alow) / low mid 是升序的if(target >= Alow && target < Amid)high = mid-1;elselow = mid+1;else/ mid high 是升序的if(target > Amid && target <= Ahigh)

87、low = mid+1;elsehigh = mid-1;return -1;如果这样的数组中存在重复元素,还能使用二分吗?答案是不能。请看几个例子1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1这些都是有第一个数组旋转一次变化来的,我们不能通过二分确定是否存在元素1.10,问题:一个有序(升序)数组,没有重复元素,在某一个位置发生了旋转后,求最小值所在位置如果中间元素小于左端元素,则最小值在左半区间内(包含中间元素);如果中间元素大于右端元素,则最小值在右半区间内(包含中间元素)。请参考实现代码

88、与注释。cpp view plain copyprint?1. int searchMinInRotatedArray(int A, int n)   2.   3.     if(n = 1)  4.         return 0;  5.     int low

89、 = 0, high = n-1;  6.     while(low < high-1) / 保证mid != low且mid != high  7.       8.         int mid = low

90、+(high-low)>>1);  9.         if(Amid < Alow) / 最小值在lowmid  10.             high = mid;  11.       

91、60; else / Amid > Alow, / 最小值在mid和high之间  12.             low = mid;  13.       14.     return Alow < Al

92、ow+1 ? low : low+1;  15.   int searchMinInRotatedArray(int A, int n) if(n = 1)return 0;int low = 0, high = n-1;while(low < high-1) / 保证mid != low且mid != highint mid = low+(high-low)>>1);if(Amid < Alow) / 最小值在lowmidhigh = mid;else / Amid > Alow,

93、/ 最小值在mid和high之间low = mid;return Alow < Alow+1 ? low : low+1;11,问题:一个有序(升序)数组,没有重复元素,在某一个位置发生了旋转后,求第k(k > 0)小元素的位置我们可以利用上一题的解答,求出最小值所在位置后,便可以求出第k小元素。请参考实现代码与注释cpp view plain copyprint?1. int searchKthInRotatedArray(int A, int n, int k)   2.  &#

94、160;3.     int posMin = searchMinInRotatedArray(A, n);  4.     return (posMin+k-1)%n;  5.   int searchKthInRotatedArray(int A, int n, int k) int posMin = searchMinInRotatedArray(A, n);return (posMin+k-1)%n

95、;12,查找旋转数组的最小数字题目:即找分界点,比如3 4 5 1 2,返回的是位置3。以题目中的旋转数组为例,3,4,5,1,2,我们可以有序数组经过旋转以后被分割为两段有序的数组,比如此处被分为3,4,51,2这样连个数组,并且前半段数组中的数字肯定大于等于后半段的数组。我们找中间元素amid,让其跟元素首元素alow和尾元素ahigh比较,如果大于首元素alow,则中间元素属于前半段有序数组;如果小于尾元素ahigh,那么中间元素就是后半段的元素。这里我们设定两个指针start和end分别指向数组的首尾元素,然后当start指向前半段最后一个元素,end指向后半段第一个元素,这是程序就找

96、到了数组中的最小元素,就是end指向的那个数,程序的出口就是 end-start=1。cpp view plain copyprint?1. int bSearchMinValue(int a, int low, int high)  2.     /终止递归条件是low和high差1,原因是后面mid都不是+1-1处理的  3.     if(low+1=high)  4.     

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论