数据结构总结之二分
2017-12-16 16:56
330 查看
1.找惟一的一个与x相等的元素的位置
2.找第一个与x相等的元素位置
3.找到最后一个与x相等的元素位置
4.找到第一个大于等于x的元素位置
5.找到第一个大于x的元素位置
6.找到最后一个小于等于x的元素位置
7.找最后一个小于x的元素位置
8.要用二分,首先要构造一个单调性的数组,比如这题(当然也有其他方法)
uva10706
构造的s[i]数组代表112123123412345123456123……i的i所在的位置。
9.我们在构造数组的时候,要注意数组不能太大,怎么解决这个问题呢?——移项。例如:hdu4282
一开始,我构造的数组是x^z+y^z+x*y*z.也就是用三层循环构造数组,结果爆内存。我们可以这样:输入一个k,循环z和x,这样对于每一个z和x,构造的数组就是y^z+x*y*z,然后找与k-x^z相等的y,找到了答案就+1.
10.如果题目让求满足某一条件的最小值,也是用二分法的,比如uva11413
11.还要注意的有二分法只能对于int型,二分上限下限也要找对。如:uva11516
int search(int *arr, int n, int key) { int left = 0, right = n-1; while(left<=right) { int mid = left + ((right - left) >> 1);//防止溢出 if (arr[mid] == key) return mid; else if(arr[mid] > key) right = mid - 1; else left = mid + 1; } return -1; }
2.找第一个与x相等的元素位置
int searchFirstEqual(int *arr, int n, int key) { int left = 0, right = n-1; while(left < right) { int mid = (left+right)/2; if(arr[mid] > key) right = mid - 1; else if(arr[mid] < key) left = mid + 1; else right=mid; } if(arr[left] == key) return left; return -1; }
3.找到最后一个与x相等的元素位置
int searchLastEqual(int *arr, int n, int key) { int left = 0, right = n-1; while(left<right-1) { int mid = (left+right)/2; if(arr[mid] > key) right = mid - 1; else if(arr[mid] < key) left = mid + 1; else left=mid; } if( arr[left]<=key && arr[right] == key) return right; if( arr[left] == key && arr[right] > key) return left; return -1; }
4.找到第一个大于等于x的元素位置
int searchFirstEqualOrLarger(int *arr, int n, int key) { int left=0, right=n-1; while(left<=right) { int mid = (left+right)/2; if(arr[mid] >= key) right = mid-1; else if (arr[mid] < key) left = mid+1; } return left; }
5.找到第一个大于x的元素位置
int searchFirstLarger(int *arr, int n, int key) { int left=0, right=n-1; while(left<=right) { int mid = (left+right)/2; if(arr[mid] > key) right = mid-1; else if (arr[mid] <= key) left = mid+1; } return left; }
6.找到最后一个小于等于x的元素位置
int searchLastEqualOrSmaller(int *arr, int n, int key) { int left=0, right=n-1; while(left<=right) { int m = (left+right)/2; if(arr[m] > key) right = m-1; else if (arr[m] <= key) left = m+1; } return right; }
7.找最后一个小于x的元素位置
int searchLastSmaller(int *arr, int n, int key) { int left=0, right=n-1; while(left<=right) { int mid = (left+right)/2; if(arr[mid] >= key) right = mid-1; else if (arr[mid] < key) left = mid+1; } return right; }
8.要用二分,首先要构造一个单调性的数组,比如这题(当然也有其他方法)
uva10706
构造的s[i]数组代表112123123412345123456123……i的i所在的位置。
#include<iostream> #include<string> #include <stdio.h> #include <stack> using namespace std; long long s[100000]; long long n,i; int f(int x) { if(x==1) return 1; long long cnt=s[x-1]-s[x-2]; while(x) { x/=10; cnt++; } return cnt; } int Bsearch(int x) { int h=i; int l=1; while(h>=l) { int mid=(h+l)/2; if(s[mid]>=x) h=mid-1; else l=mid+1; } return l; } int out_result(int pos) { int cnt=n-s[pos-1]; for(int i=1;i<=pos;i++) { int tmp=i; stack<int> s;//这里用栈得到了一个数的第一个第二个……第i个数字 while(tmp) { s.push(tmp%10); tmp/=10; } while(!s.empty()) { int ans=s.top();s.pop(); if(--cnt==0) return ans; } } } int main() { for(i=1;s[i-1]<= 2147483647;i++) { s[i]=s[i-1]+f(i); } int t;cin>>t; while(t--) { scanf("%d",&n); int pos=Bsearch(n); printf("%d\n",out_result(pos)); } return 0; }
9.我们在构造数组的时候,要注意数组不能太大,怎么解决这个问题呢?——移项。例如:hdu4282
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const __int64 maxn=1<<16; __int64 k; __int64 a[maxn][32]; const __int64 MAX=2147483648;//1<<31必须这样写…… void init() { memset(a,0,sizeof(a)); for(int i=1;i<maxn;i++) a[i][1]=i; for(int i=1;i<maxn;i++) for(int j=2;j<32;j++) { a[i][j]=a[i][j-1]*i; if(a[i][j]>=MAX) { a[i][j]=0; break; } } } bool f(__int64 sum,__int64 e,__int64 x) { __int64 l,h,mid; l=x+1; h=maxn; while(l<=h) { mid=(h+l)/2; if(a[mid][e]==0) { h=mid-1; continue; } __int64 tmp=a[mid][e]+e*mid*x; if(tmp==sum) return true; else if(tmp>sum) h=mid-1; else l=mid+1; } return false; } int main() { init();//设置乘方表,大于等于2的31次方的都为0 while(~scanf("%I64d",&k) && k) { __int64 ans=0; __int64 sum=0; __int64 e; for(__int64 x=1;x<maxn;x++) for(e=2;e<32;e++) { if(a[x][e]==0) break; sum=k-a[x][e]; if(sum<=0) break; if(f(sum,e,x)) ans++; } printf("%I64d\n",ans); } return 0; }
一开始,我构造的数组是x^z+y^z+x*y*z.也就是用三层循环构造数组,结果爆内存。我们可以这样:输入一个k,循环z和x,这样对于每一个z和x,构造的数组就是y^z+x*y*z,然后找与k-x^z相等的y,找到了答案就+1.
10.如果题目让求满足某一条件的最小值,也是用二分法的,比如uva11413
#include <iostream> #include <cstdio> #include <cstring> using namespace std; int v[1001]; int n,m; int container_num(int size) { int sum=0; int count=0; for(int i=0;i<n;i++) { if(sum+v[i]>size) { sum=v[i];//当“够了”sum立即变成下一个的sum,然后次数+1 count++; } else sum+=v[i]; } return count+1; } int main() { while(scanf("%d%d",&n,&m)!=EOF) { int max=0; int sum=0; for(int i=0;i<n;i++) { scanf("%d",&v[i]); sum+=v[i]; if(max<v[i]) max=v[i]; } int l=max; int h=sum; int mid; while(l<h) { mid=(l+h)/2; if(container_num(mid)<=m) h=mid;//仔细想想为什么不是mid-1? else l=mid+1; } ; printf("%d\n",l); } }
11.还要注意的有二分法只能对于int型,二分上限下限也要找对。如:uva11516
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int loc[100005]; int n,m; bool f(int mid) { int start=loc[0]; int need=1; for(int i=0; i<m; i++) if(loc[i]>start+mid) { need++; start=loc[i]; } if(need>n) return false; else return true; } int main() { int t; cin>>t; while(t--) { scanf("%d%d",&n,&m); for(int i=0; i<m; i++) scanf("%d",&loc[i]); sort(loc,loc+m); int hi,lo,mid; hi=(loc[m-1]-loc[0])*2; lo=0; while(hi>lo) { mid=(hi+lo)/2; if(!f(mid))//因为位置都是int,所以直径也是int型,故可以二分 lo=mid+1; else hi=mid; } printf("%.1f\n",lo/2.0); } return 0; }
相关文章推荐
- Redis内部数据结构总结(3)ziplist
- 数据结构要点归纳总结(转)
- 数据结构总结(一):一种特殊的有序队列
- 数据结构 第一章 学习感受与总结
- 数据结构复习总结
- 《数据结构》第二章线性表学习总结
- c数据结构线性表的总结
- 严蔚敏-数据结构-递归算法总结
- 数据结构和算法总结(一):广度优先搜索BFS和深度优先搜索DFS
- 数据结构总结
- 【数据结构】vector用法总结
- 数据结构 之 并查集 总结
- 数据结构总结
- 【数据结构】ArrayList原理及实现学习总结
- Java常用容器(数据结构)总结
- 【数据结构】LinkedList原理及实现学习总结
- 数据结构 学期末总结
- 《数据结构》严蔚敏版 读书总结
- 数据结构与程序设计 第一章 编成原理 总结
- 数据结构题目总结