void sort(int a[], int n){ if(n<=1) return; int m = a[0], l = 1, r = n-1; while(l<r){ while(l<r && a[l]<=m) l++; while(l<r && a[r]>m) r--; if(l<r) { int tmp = a[l]; a[l] = a[r], a[r] = tmp; } } /* [1, l) no bigger than m,(r, n-1] bigger than m, l==r */ assert(l == r); if(a[r] > m) r--; /* now a[r] <= m, r>=0 */ a[0] = a[r], a[r] = m; sort(a, r); sort(a+r+1, n-r-1); }
void sort(int a[], int n){ if(n<=1) return; int m = a[0], l = 0, r = n-1; // no less than 2 elements in a[], l=0<r while(l<r){ while(l<n && a[l]<=m) l++;// l skip 0, and may stop in bigger than r=n-1 while(r>=0 && a[r]>m) r--;// r stop in no smaller than l=0, since a[0]<=m if(l<r) {// then l and r can't overindex int tmp = a[l]; a[l] = a[r], a[r] = tmp; } } /* a[r] no bigger than m, (r, n-1] bigger than m */ a[0] = a[r], a[r] = m; sort(a, r); sort(a+r+1, n-r-1); }
class Solution { public: void sortColors(int A[], int n) { int l = 0, r; for(int m=0; m<2; m++){ r=n-1; while(l<r){//l是划分点:A[l]是第一个大于m的元素,并且l就算越界,也会有r约束它使之跳过while循环 while(l<r && A[l]<=m) l++; while(l<r && A[r]>m) r--; if(l<r) { int t = A[l]; A[l]=A[r], A[r]=t;} } } } };
但是奇怪的是上面的代码没有这个快? O(n*1)>O(n*3)....
void sortColors(int A[], int n) { for(int m=0; m<2; m++){ int l = 0, r = n-1; while(l<r){ while(l<r && A[l]<=m) l++; while(l<r && A[r]>m) r--; if(l<r) { int t = A[l]; A[l]=A[r], A[r]=t;} } } }
如 轮转数组3 4 5 1 2, 返回 1
二分方法:
l =0, r = n-1, t = a[r] 跳过a[l]==t的l assert(a[l]!=t) //l在左半边 或 右半边 while ... if a[mid]>t: l = mid+1 //mid落在左半边 if a[mid]<=t: r = mid //mid落在右半边,注意右半边的mid有可能是答案,r=mid而不是mid-1
注意存在这种情况 x x x x1 x2 .. xm, y1 y2 .. yn x x x x ,即两边都存在 重复x, 如 3 3 4 5 1 2 3 3 3,
这种情况的处理办法是 先跳过左边的 a[l]==t 的l
class Solution { public: int findMin(vector<int> &num) { int l = 0, r = num.size() - 1; int t = num[r]; //while(l<r) if(num[l] == t) l++; //@error while(l<r && num[l] == t) l++; while(l<r){ int mid = (l+r)/2; if(num[mid]>t) l = mid+1; else r = mid; // if num[mid] == t, then a[mid, r] == t, let r = mid } return num[l]; } };
class Solution { public: double findMedianSortedArrays(int A[], int m, int B[], int n) { int t = m+n; if(t%2){ return findK(A, m, B, n, (m+n-1)/2+1); } return (findK(A, m, B, n, (m+n-1)/2+1) + findK(A, m, B, n, (m+n-1)/2+2))/2.0; } int findK(int A[], int m, int B[], int n, int k){ assert(k>=1 && k<= m+n); int l = m-1, r = n-1; while(l>=0 && r>=0 && l+r+2>=k+1){ int m1 = (k+1)*(l+1)/(l+r+2)-1, m2 = k-1-m1; if(m1<0) m1=0, m2 = k-1;//@error: not if(m2>r) m2=r, m1=k-1-m2; if(A[m1]>B[m2]) l = m1 - 1; else r = m2 -1; } if(l>=0 && r>=0) return max(A[l], B[r]); //return l<0?B[r]:A[l];//@error: should be B[k-1] or A[k-1]. return l<0?B[k-1]:A[k-1]; } };
class Solution { public: int sqrt(int x) { int l =0, r= x; while(l<r){ int mid = (l+r)/2; long long int t = mid*(long long int)mid; if(t > x) { r = mid-1; } else{//t<=x if( t == x || (mid+1)*(long long int)(mid+1) > x) return mid; // if mid+1 is too big l = mid+1; } } return l; } };
题目来自九章算法
int find(int a[], int n){ int l = 1, r = n-2; while(l<=r){ int mid =(l+r)/2; if(a[mid]>a[mid+1] && a[mid] > a[mid-1]) return mid; if(a[mid]>a[mid+1]) {r=mid-1;} else l = mid+1; } return -1; // not found }