二分法总结

 1 class Solution:
 2     # @param nums: The integer array
 3     # @param target: Target number to find
 4     # @return the first position of target in nums, position start from 0 
 5     def binarySearch(self, nums, target):
 6         if len(nums) == 0:
 7             return -1
 8             
 9         start, end = 0, len(nums) - 1
10         while start + 1 < end:
11             mid = (start + end) // 2
12             if nums[mid] < target:
13                 start = mid
14             else:
15                 end = mid
16                 
17         if nums[start] == target:
18             return start
19         if nums[end] == target:
20             return end
21         return -1
python模板
 1 #include <vector>
 2 using namespace std;
 3 
 4 class Solution {
 5 public:
 6     /**
 7      * @param array source array
 8      * @param target target to search
 9      * @return the first occurrence position of target 
10      */
11     int binarySearch(vector<int> &A, int target) {
12         if (A.size() == 0) {
13             return -1;
14         }
15 
16         int start = 0;
17         int end = A.size() - 1;
18         int mid;
19 
20         while (start + 1 < end) {
21             mid = start + (end - start) / 2;
22             if (A[mid] == target) {
23                 end = mid;
24             } else if (A[mid] < target) {
25                 start = mid;
26             } else if (A[mid] > target) {
27                 end = mid;
28             }
29         }
30 
31         if (A[start] == target) {
32             return start;
33         }
34         if (A[end] == target) {
35             return end;
36         }
37 
38         return -1;
39     }
40 };
C++模板

死循生:when target is the last position of the range
nums = [1,1], target = 1
使用 start < end 如何都会出死循

 

类型1:裸题

 

704. Binary Search

 1 class Solution:
 2     def bd(self, nums, target, start, end):
 3         while(start+1<end):
 4             mid=(start+end)//2
 5             if(nums[mid]==target):
 6                 return mid
 7             if(nums[mid]>target):
 8                 end=mid
 9             if(nums[mid]<target):
10                 start=mid
11         if(nums[start]==target):
12             return start
13         if(nums[end]==target):
14             return end
15         return -1
16 
17     def search(self, nums, target):
18         """
19         :type nums: List[int]
20         :type target: int
21         :rtype: int
22         """
23         sl=len(nums)-1
24         if(sl==-1):
25             return -1
26         ans=self.bd(nums, target, 0, sl)
27         return ans
View Code

 

34. Find First and Last Position of Element in Sorted Array

稍微改改边界就行了

 1 class Solution:
 2     def fbs(self, nums, target, start, end):
 3         tmp=999999
 4         while(start+1<end):
 5             mid=(start+end)//2
 6             if(nums[mid]==target):
 7                 tmp=mid
 8                 end=mid
 9             if(nums[mid]>target):
10                 end=mid
11             if(nums[mid]<target):
12                 start=mid
13         if(nums[start]==target):
14             tmp=min(tmp,start)
15         if(nums[end]==target):
16             tmp=min(tmp, end)
17         if(tmp==999999):
18             return -1
19         else:
20             return tmp
21 
22     def lbs(self, nums, target, start, end):
23         tmp=-1
24         while(start+1<end):
25             mid=(start+end)//2
26             if(nums[mid]==target):
27                 tmp=mid
28                 start=mid
29             if(nums[mid]>target):
30                 end=mid
31             if(nums[mid]<target):
32                 start=mid
33         if(nums[start]==target):
34             tmp=max(tmp,start)
35         if(nums[end]==target):
36             tmp=max(tmp, end)
37         return tmp
38 
39     def searchRange(self, nums, target):
40         """
41         :type nums: List[int]
42         :type target: int
43         :rtype: List[int]
44         """
45         if(len(nums)==0):
46             return([-1,-1])
47         fs=self.fbs(nums, target, 0, len(nums)-1)
48         ls=self.lbs(nums, target, 0, len(nums)-1)
49         return([fs, ls])
View Code

 

 

类型2:OOXX
给定一个数组(数据类似OOOOOOXXXXXXXXX),求中第一个/最后一个足某个条件(X)的位置

 

278. First Bad Version

还是用二分法,把条件魔改一下就行了

改成while(start<end)是为了不漏掉剩余区间长度为2的情况。同时为了防止死循环,start也得改成mid+1

 1 # The isBadVersion API is already defined for you.
 2 # @param version, an integer
 3 # @return a bool
 4 # def isBadVersion(version):
 5 
 6 class Solution:
 7     def bs(self, start, end):
 8         cnt=0
 9         while(start<end):
10             mid=(start+end)//2
11             cnt+=1
12             print(start,end,mid,cnt)
13             if(isBadVersion(mid)):
14                 end=mid
15             else:
16                 start=mid+1
17         return start
18 
19     def firstBadVersion(self, n):
20         """
21         :type n: int
22         :rtype: int
23         """
24         if(n<=1):
25             return n
26         return self.bs(1,n)
View Code

 

658. Find K Closest Elements

先用二分找到数组内离target最近的元素下标,然后用O(k)的时间,用两个指针从中间向外扩展再找离得最近的k-1个元素即可。最后排个序输出

 1 class Solution:
 2     def bs(self, x, arr, start, end):
 3         while (start+1<end):
 4             mid=(start+end)//2
 5             if(arr[mid]==x):
 6                 return mid
 7             if(arr[mid]<x):
 8                 start=mid
 9             if(arr[mid]>x):
10                 end=mid
11         ansx=abs(arr[start]-x)
12         ans=start
13         while (ans<end and abs(arr[ans+1]-x)<ansx):
14             ans+=1
15             ansx=abs(arr[ans]-x)
16         return ans
17 
18 
19     def findClosestElements(self, arr, k, x):
20         """
21         :type arr: List[int]
22         :type k: int
23         :type x: int
24         :rtype: List[int]
25         """
26         pos=self.bs(x, arr, 0, len(arr)-1)
27         print(pos)
28         pl=pos-1
29         pr=pos+1
30         tk=k-1
31         ans=[arr[pos]]
32         while(tk):
33             if(pl<0 and pr<=len(arr)-1):
34                 ans.append(arr[pr])
35                 pr+=1
36             if(pl>=0 and pr>len(arr)-1):
37                 ans.append(arr[pl])
38                 pl-=1
39             if(pl>=0 and pr<=len(arr)-1):
40                 if(abs(arr[pr]-x)<abs(arr[pl]-x)):
41                     ans.append(arr[pr])
42                     pr+=1
43                 else:
44                     ans.append(arr[pl])
45                     pl-=1
46             tk-=1
47         ans.sort()
48         return ans
49 
50 sl=Solution()
51 aa=[0,0,0,1,3,5,6,7,8,8]
52 print(sl.findClosestElements(aa,2,2))
View Code

 

852. Peak Index in a Mountain Array

ooooPxxxxx题,一样的套路

o: 单调递增 x: 单调递减

注意处理mid正好是peak的情况

 1 class Solution:
 2     def peakIndexInMountainArray(self, A):
 3         """
 4         :type A: List[int]
 5         :rtype: int
 6         """
 7         la=len(A)
 8         start=0
 9         end=la-1
10         while(start+1<end):
11             mid=(start+end)//2
12             if(A[mid-1]<A[mid] and A[mid]>A[mid+1]):
13                 return mid
14             if(A[mid-1]<A[mid] and A[mid]<A[mid+1]):
15                 start=mid
16             if(A[mid-1]>A[mid] and A[mid]>A[mid+1]):
17                 end=mid
18         return (start if A[start]>A[end] else end)
View Code

 

74. Search a 2D Matrix

二分两遍。第一遍找在哪一行,第二遍找具体的value

找哪一行的时候,对最后剩下的start和end判断一哈就好啦。别的和普通二分一样

 1 class Solution:
 2     def bs(self, nums, _start, _end, target, R):
 3         start=_start
 4         end=_end
 5         while(start+1<end):
 6             mid=(start+end)//2
 7             if(nums[mid]>target):
 8                 end=mid
 9             if(nums[mid]<target):
10                 start=mid
11             if(nums[mid]==target):
12                 return mid
13         if(R==1):        #search for value
14             if(nums[start]==target):
15                 return start
16             if(nums[end]==target):
17                 return end
18             return -1
19         if(R==0):        #search for range
20             if(nums[start]<=target and nums[end]>target):
21                 return start
22             if(nums[end]<=target):
23                 return end
24             else:
25                 return -1
26 
27     def searchMatrix(self, mm, target):
28         """
29         :type mm: List[List[int]]
30         :type target: int
31         :rtype: bool
32         """
33         if(len(mm)==0):
34             return False
35         ml=len(mm[0])
36         if(ml==0):
37             return False
38         fst=[xx[0] for xx in mm]
39         rg=self.bs(fst,0,len(fst)-1,target,0)
40         print(rg)
41         ans=self.bs(mm[rg],0,ml-1,target,1)
42         if(ans==-1):
43             return False
44         else:
45             return True
46 
47 sl=Solution()
48 mm=[[5,6,7,8]]
49 print(sl.searchMatrix(mm,8))
View Code

 

240. Search a 2D Matrix II

这题其实不是二分....

O(M+N)的方法:类似dp一样转移当前位置

[i][j] -> [i][j+1] , if A[i][j]<target
          [i-1][j] , if A[i][j]>target

初始放在最左下角,即[len(A)-1][0]处

 1 class Solution:
 2     def searchMatrix(self, matrix, target):
 3         """
 4         :type matrix: List[List[int]]
 5         :type target: int
 6         :rtype: bool
 7         """
 8         lm=len(matrix)
 9         if(lm==0):
10             return False
11         ln=len(matrix[0])
12         if(ln==0):
13             return False
14 
15         tx=lm-1
16         ty=0
17         for i in range(0,lm+ln):
18             if(tx<0 or ty>=ln):
19                 return False
20             tmp=matrix[tx][ty]
21             #print(tx,ty,tmp)
22             if(tmp==target):
23                 return True
24             if(tmp>target):
25                 tx-=1
26             if(tmp<target):
27                 ty+=1
28 
29 sl=Solution()
30 sl.searchMatrix([[1]],1)
View Code

 

https://www.lintcode.com/problem/search-for-a-range/description

同LeetCode 34. Find First and Last Position of Element in Sorted Array ,   往上滑滚动条就有......

 

https://www.lintcode.com/problem/total-occurrence-of-target/

没权限呜呜呜...

 

302 Smallest Rectangle Enclosing Black Pixels

传送门:https://www.lintcode.com/problem/smallest-rectangle-enclosing-black-pixels/description

 

类型3:

 

162. Find Peak Element

 

33. Search in Rotated Sorted Array

 三次二分...但加起来还是算logN嘛  【摊手

第一次:找数组中的最小值,记最小值的下标为idx

 1 将rotated array的数据值按xy坐标系画出来看一哈,大概是这样的:
 2 
 3                  '   |
 4               '      |
 5            '         |
 6   '[fst]            |
 7 ---------------------------------------------------------------
 8                      |                       '[lst]
 9                      |                    '
10                      |                 '
11                      |             '
12                      |  '[最小]
13 
14 可以发现,最小值左半边的数都是>=first的,最小值及其右半边的数都是<=lst的
15 按照OOOOXXXX的思路,通过二分缩小start~end的范围。注意循环里不需要判断mid是不是最小值点了(因为不好判断)
16 最后退出循环时,start~end的区间范围最多是2,且其中肯定包含最小值。手动min判断一下即可
17 
18 
19     def findmin(self, nums):    #return index of min value
20         nl=len(nums)
21         fst=nums[0]
22         lst=nums[nl-1]
23         start=0
24         end=nl-1
25         while(start+1<end):
26             mid=(start+end)//2
27             if(nums[mid]>=fst):
28                 start=mid
29             if(nums[mid]<=lst):
30                 end=mid
31         return(start if nums[start]<nums[end] else end)

第二次:在有序数组nums[0..idx-1]中找target

第三次:在有序数组nums[idx..len-1]中找target

 1 class Solution:
 2 
 3     def findmin(self, nums):    #return index of min value
 4         nl=len(nums)
 5         fst=nums[0]
 6         lst=nums[nl-1]
 7         start=0
 8         end=nl-1
 9         while(start+1<end):
10             mid=(start+end)//2
11             if(nums[mid]>=fst):
12                 start=mid
13             if(nums[mid]<=lst):
14                 end=mid
15         return(start if nums[start]<nums[end] else end)
16 
17     def bs(self, nums, _start, _end, target):
18         start=_start
19         end=_end
20         while(start+1<end):
21             mid=(start+end)//2
22             if(nums[mid]==target):
23                 return mid
24             if(nums[mid]<target):
25                 start=mid
26             if(nums[mid]>target):
27                 end=mid
28         if(nums[start]==target):
29             return start
30         if(nums[end]==target):
31             return end
32         return -1
33 
34     def search(self, nums, target):
35         """
36         :type nums: List[int]
37         :type target: int
38         :rtype: int
39         """
40         if(len(nums)==0):
41             return -1
42         if(len(nums)==1):
43             return(0 if nums[0]==target else -1)
44         idx=self.findmin(nums)
45         #print(idx)
46         ans1=self.bs(nums,0,idx-1,target) if idx>0 else -1
47         #print(0,idx-1,ans1,nums)
48         ans2=self.bs(nums,idx,len(nums)-1,target) if idx<=len(nums)-1 else -1
49         #print(idx,len(nums)-1,ans2,nums)
50         return (ans1 if ans1!=-1 else ans2)
51 
52 sl=Solution()
53 print(sl.search([3,1], 1))
View Code

 

补充:快速幂

https://leetcode.com/problems/powx-n/

 1 class Solution:
 2     def myPow(self, x, n):
 3         """
 4         :type x: float
 5         :type n: int
 6         :rtype: float
 7         """
 8         inc=x
 9         ans=1
10         N=int(n)
11         flag=False
12         if(N==0):
13             return 1
14         if(N<0):
15             N=-N
16             flag=True
17         while(N>1):
18             if(N%2!=0):
19                 ans=ans*inc
20             inc=inc*inc
21             N=N//2
22             #print(inc,ans,N)
23         ans=inc*ans
24         if(flag):
25             ans=1/ans
26         return ans
27 
28 sl=Solution()
29 xx=sl.myPow(2,-2)
30 print(xx)
View Code

 

类型4:二分答案

 Copy Books

https://www.lintcode.com/problem/copy-books/description

 

三步翻转法

http://www.lintcode.com/problem/recover-rotated-sorted-array/

题意:对于类似4,5,1,2,3的数组,in place还原成1,2,3,4,5

sol:先找到5和1之间的这个位置(可以用二分法),然后按以下策略翻转数组:

1. 分别翻转两部分

45123

54321

2. 翻转整个数组

54321

12345

 http://www.lintcode.com/problem/rotate-string/

abcde fg  ->  edcba gf

edcbagf  ->  fgabcde

转载于:https://www.cnblogs.com/pdev/p/9907170.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值