二分法相关
1.旋转数组找最小值
{3,4,5,1,2}为{1,2,3,4,5}的一个旋转数组
public int minNumberInRotateArray(int [] array) { int low = 0 ; int high = array.length - 1; while(low < high){ int mid = low + (high - low) / 2; if(array[mid] > array[high]){ low = mid + 1; }else if(array[mid] == array[high]){ high = high - 1; }else{ high = mid; } } return array[low]; }
2.去一个排序数组中找距离target最近的节点的下标(二分法)
public int closestNumber(int[] A, int target) { // write your code here if(A == null || A.length == 0 || target < A[0]) return 0; if(target > A[A.length - 1]) return A.length - 1; int l = 0, r = A.length - 1; while(l < r - 1){ int mid = l + (r - l) / 2; if(A[mid] == target) return mid; else if(A[mid] > target) r = mid; else l = mid; } if(Math.abs(target - A[l]) < Math.abs(target - A[r])) return l; else return r; }
依次给出n个正整数A1,A2,… ,An,将这n个数分割成m段,每一段内的所有数的和记为这一段的权重, m段权重的最大值记为本次分割的权重。问所有分割方案中分割权重的最小值是多少?
public int binarySearch(int[] a,int m) { int n=a.length; int sum=0; int maxa=0; for(int i=0;i<n;i++) { sum+=a[i]; maxa=Math.max(maxa, a[i]); } //被分割的数只可能是最大值和和之间的值 int left=maxa,right=sum; int countm=0; while(left<right) { int mid=(left+right)/2; int temp=0; countm=1;//计算当前被分割的个数 for(int i=0;i<n;i++) { if(a[i]+temp>mid) { temp=0; countm++; } temp+=a[i]; } if(countm>m)//被分割的次数大于原先的,说明我们安排的mid小了 left=mid+1; else right=mid; } return left; }
3.找这样一个数组第k小的数字
3 3 3(n,m,k)
1 2 3
2 4 6
3 6 9
二分查找,去每一列里面查找比mid小的,统计个数,如果总个数比k大,就证明,end大了,向左移动,如果比k小了,start小了,向右移动(感觉把二分法用到极致了)
public int findKthNumber(int m, int n, int k) { int st = 1, ed = m * n; while (st < ed) { int mid = (st + ed) / 2; if (largeEnough(mid, m, n, k)) ed = mid; else st = mid + 1; } return ed; } private boolean largeEnough(int x, int m, int n, int k) { int cnt = 0; for (int i = 1; i <= m; i++) cnt += Math.min(x / i, n); return cnt >= k; }
4.去循环有序数组里面找目标为target的数组的下标
4 5 1 2 3这种
public int search(int[] a,int n,int target) { int left = 0, right = n-1; while(left<=right) { int mid = left + ((right-left)/2); if(a[mid] == target) return mid; if(a[left] <= a[mid])//转折点在右半边,左边是有序的,应该尝试用左边的数去比较 { if(a[left] <= target && target < a[mid]) right = mid - 1; else left = mid + 1; } else //转折点在左半边,右边是有序的,尝试用右边的数去比较 { if(a[mid] < target && target <= a[right]) left = mid + 1; else right = mid - 1; } } return -1;//没有找到 }
本文来自博客园,作者:LeeJuly,转载请注明原文链接:https://www.cnblogs.com/peterleee/p/11205648.html

浙公网安备 33010602011771号