• 二分查找极其变形算法



    二分查找是典型的分治法的应用,要求待查序列排好序,这里都按照从小到大排列处理,查找时间代价o(log(n)).
    思路和中间的数字比较,如果相等则找到,如果<则在左边找,如果>则在右边找。
    分治及许多计算机算法的核心就是将问题设法转化为相同的形式问题而规模减小,即子问题。能够找到规模减小的子问题,意味着问题的解决。
    注意分治不一定非要递归,如果每次只走一个分支,那么循环的写法也非常简单,是更好的写法。
     1 def bsearch(li, val):
     2 
     3     start = 0
     4 
     5     end = len(li) - 1
     6 
     7     while(start <= end):
     8 
     9         middle = int((start + end)/2)
    10 
    11         if val == li[middle]:
    12 
    13             return middle
    14 
    15         if val < li[middle]:
    16 
    17             end = middle - 1
    18 
    19         else:
    20 
    21             start = middle + 1
    22 
    23 
    24     return -1
    二分变形1
    在数组中查找val,有可能数组中有多个相同的val,返回第一个的位置
    方法1,二分查找val,找到后向左线性扫描直到遇到更小的。
    方法2,找到val以后,对左边的数组继续二分查找直到找到第一个位置
    其它方法? TODO参考一下stl的lower bound
    下面给出方法2的解法。
     1 """find the first val like li avove search 3 will return 2"""
     2 
     3 def bsearch2(li, val):
     4 
     5     start = 0
     6 
     7     end = len(li) - 1
     8 
     9     find = -1
    10 
    11     while(start <= end):
    12 
    13         middle = int((start + end)/2)
    14 
    15         if val == li[middle]:
    16 
    17             end = middle - 1
    18 
    19             find = middle
    20 
    21         if val < li[middle]:
    22 
    23             end = middle - 1
    24 
    25         else:
    26 
    27             start = middle + 1
    28 
    29     return find    
    二分变形2
    将排好序的数组移位,而且不知道具体的移位位置
    如1 , 2, 3, 4, 5, 6, 7
    移位后可能为
    6 , 7, 1, 2, 3, 4, 5     //list1
    3, 4, 5, 6, 7, 1, 2     //list2
    这样查找过程中,要注意如何能够找到相同形式规模缩小的子问题呢?
    仍然二分查找,但是每次下一步查找的区间的确定,就不仅仅由待查找的val和当前数组中间值的关系确定了,要考虑数组的头尾元素值。
    例如 list1中查找 7, 那么先和2 比较发现较大, 但是下一步不能去右边区间找,因为7 > list1的首元素了,所以应该在左边区间查找。
    注意区分list1,list2的不同 list1的中间值小于list1的首元素,意味着中间值在较小的序列中。
    而list2的中间值大于首元素,意味着中间值在较大的序列中。
     1 def bsearch3(li, val):
     2 
     3     start = 0
     4 
     5     end = len(li) - 1
     6 
     7     while(start <= end):
     8 
     9         mid = int((start + end)/2)
    10 
    11         #print '*', mid, val, li[mid]
    12 
    13         if val == li[mid]:
    14 
    15             return mid
    16 
    17         if val == li[start]:
    18 
    19             return start
    20 
    21         if val == li[end]:
    22 
    23             return end
    24 
    25         if val < li[mid]:
    26 
    27             if li[mid] < li[start]:                 #like  6 7 1 .2. 3 4 5
    28 
    29                 end = mid - 1                       #here to find 1
    30 
    31             else:               #li[mid] >= li[start]like  3 4 5 .6. 7 1 2
    32 
    33                 if (val < li[start]):               #here to find 2
    34 
    35                     start = mid + 1
    36 
    37                 else:
    38 
    39                     end = mid - 1                   #here to find 4
    40 
    41         else:               #val > li[mid]
    42 
    43             if li[mid] < li[start]:                 #like  6 7 1 .2. 3 4 5
    44 
    45                 if val < li[end]:                   #here to find 3 or 4 
    46 
    47                     start = mid + 1
    48 
    49                 else:                               
    50 
    51                     end = mid - 1                   #here to find 7
    52 
    53             else:                                   #like 3 4 5 .6. 7 1 2
    54 
    55                 start = mid + 1                     #here to find 7
    56 
    57     return -1
  • 相关阅读:
    并发量,tps,qps
    MYSQL安装和配置
    python 生成随机数的几种方法
    python 判断是字母的多种方法
    python实战,
    linux工作常用命令
    apache http server安装
    .py与.pyc文件区别
    上传本地文件到linux
    ms
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1570149.html
Copyright © 2020-2023  润新知