

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


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 };
死循环的发生: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
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])
类型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)
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))
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)
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))
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)
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))
补充:快速幂
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)
类型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