二分法应用
二分法应用
问题描述##
41(13分)给定一个含叫(21)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数
组中未出现的最小正整数。例如,数组(5,3,2,3]中未出现的最小正整数是1;数组1,2,3)中未出
现的最小正整数是4。要求:
(1)给出算法的基本设计思想。
(2)根据设计思想,采用C或C+语言描述算法,关键之处给出注释。
(3)说明你所设计算法的时间复杂度和空间复杂度。
<这是近年的考研题,受到二分法思想的启发就过来尝试一下。
下面我会用两种方法来解决这道问题,
普通方法
#include<stdio.h>
int main()
{
int n;
printf(“请输入一个正整数n:”);
scanf("%d",&n);
printf("\n");
int i,a[n],j,b;//i,j是循环需要,a[n]数组,b排序变换;
for(i=0;i<n;i++){//输入数组数据;
scanf("%d",&a[i]);
}
//排序
for(j=0;j<n-1;j++){
for(i=0;i<n-1;i++){
if(a[i]>a[i+1]){
b=a[i];
a[i]=a[i+1];
a[i+1]=b;
}
else continue;
}
}//时间复杂度(n-1)2=n2;
//for(i=0;i<n;i++){
//printf("%d\t",a[i]);
//}
int k=1;//k是标志;
for(i=0;i<n;i++){//找需要的最小正整数;
if(a[i]<=0){
continue;
}
else if(a[i]==1){
k++;
continue;
}
else if(a[i]>0&&a[i]>k){
printf("%d\n",k);
break;
}
else if(a[i]==k){
k++;
continue;
}
else{
printf("%d\n",k);
break;
}
}//时间复杂度n;
printf("%d\n",k);
return 0;
}
已经做好了注释,如有错误请指正。
下面就来看用二分法怎么办?
代码如下:
**#include<stdio.h>
#include<math.h>
int main()
{
int n,i;
printf(“请输入一个正整数表示数组长度n:”);
scanf("%d",&n);
int a[n];
for(i=0;i<n;i++){//数组数据读入;
scanf("%d",&a[i]);
}
//排序;
int b,j;
for(j=0;j<n-1;j++){//排序
for(i=0;i<n-1;i++){
if(a[i]>a[i+1]){
b=a[i];
a[i]=a[i+1];
a[i+1]=b;
}
else continue;
}
}
for(i=0;i<n;i++){
printf("%d\t",a[i]);
}
printf("\n");
for(i=1;i<n;i++){//让重复的数据赋值为-1;
if(a[i]==a[i-1]) a[i-1]=-1;
else continue;
}
/for(i=0;i<n;i++){
printf("%d\t",a[i]);
}/
//printf("\n");
for(j=0;j<n-1;j++){//排序
for(i=0;i<n-1;i++){//让数据赋值后再次排序;
if(a[i]>a[i+1]){
b=a[i];
a[i]=a[i+1];
a[i+1]=b;
}
else continue;
}
}
//for(i=0;i<n;i++){
// printf("%d\t",a[i]);
//}
//printf("\n");
int head=0,rear=n-1;//head为数组第一个正整数的标志,rear为数组的尾数据的标志;
for(i=0;i<n-1;i++){
if(a[i]<=0) continue;
else if(a[i]>0){
head=i;
break;
}
else if(a[n-1]<=0) break;
}
//printf("%d\n",head);
//printf("%d\n",rear);
int mid;//mid为head和rear的中间位置;
mid=(head+rear)/2;
for(;rear-head>1;){//二分法把排查目标缩小一半;
if((a[mid]-a[head])==(mid-head)){
head=mid;
mid=(head+rear)/2;
}
else if((a[rear]-a[mid])==(rear-mid)){
rear=mid;
mid=(head+rear)/2;
}
else if((a[mid]-a[head])>(mid-head)){
rear=mid;
mid=(head+rear)/2;
}
else if((a[rear]-a[mid])>(rear-mid)){
head=mid;
mid=(head+rear)/2;
}
}
if(rear-head==a[rear]-a[head]) printf("%d",a[rear]+1);
//printf("%d\n",head);
else printf("%d",a[head]+1);
return 0;
}
准备工作做得比较多,排序,查找重复的数据并重新赋值,再次排序。
主要区域在最后一次for循环,head是数组中第一个正整数的标志,rear是数组最后一个元素的标志,mid=(head+rear)/2是head和rear中间元素的标志。
每进行一次for循环就把排查目标缩小一半。直到最后rear-head==1循环就结束了。也就是目标就剩下两个元素了,如果两个元素之间有空隙,结果就是a[head]+1;否则就是a[rear]+1;
如果是考研党,按照答题要求来哦,我只是用代码实现了。君君大二了,想找个伙伴一起学习,不知道有没有,想一起的私信我哦。就是分享题目和思想。加油!