目录
题目:
给定一个含n(n>=1)个整数的数组,请设计并实现一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。
例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4。
题目分析:
1.输入数据是无序的。
2.时间上尽可能高效,代表着我们不能去对数组排序,不然就不是时间高效了。也不能一个一个找,从1开始找该数是否出现,这样的操作时间也是不够高效的。
思路解析:
要找出最小正整数,肯定要对数组中每一个数都要遍历。
首先,负数对我们的结果没有影响,所以先判断是否是负数,不是负数在进行接下来的操作。
其次,我们做一个表来检测哪些数出现过,就像签到表,出现过就在它对应的地方做一个标记。这样我们只需要遍历一边输入数组,再遍历一边签到表就能找出答案了。
如例题所示,签到表就应该长这样。
那么还有个问题,签到表应该多长呢?
这个问题十分尖锐,因为签到表至少需要装下输入元素中最大的元素,而我们又不知道表中最大元素,所以我们需要在便利一遍数组,找出最大元素。
还有个方法,那就是当扫描到下一个数,超出签到表长度的时候,我们就再创建这么多数组,给签到表加长。这个方法是最优解,这个就交给你们自己去完成了。
怎么做呢?
用签到表的顺序i来表示哪个数,便利到这个数n那么就让签到表a[n]++,让它不是0,就代表出现过。
源代码:
#include <stdio.h> //头文件
#include <stdlib.h>
#include <malloc.h>
#include <conio.h>
#define ERROR 0 //函数结果状态代码
#define OK 1
#define EQUAL 1
#define OVERFLOW -1
#define LIST_INIT_SIZE 100 //顺序表存储空间的初始分配量
#define LISTINCREMENT 10 //顺序表存储空间的分配增量
typedef int Status; //Status为函数返回值类型,其值为函数结果状态代码
struct NUMBER {
int number;
};
typedef struct NUMBER ElemType;//顺序表中数据元素类型
struct LIST {
ElemType *elem; //顺序表的存储空间基址
int length; //当前长度
int listsize; //当前分配的存储容量
};
typedef struct LIST SqList; //线性表的顺序存储结构定义
Status InitList_SqList(SqList *); //构造一张新的顺序表L
Status ListInsert_SqList(SqList *, int, ElemType ); //在顺序表L的第i个元素前插入新元素e
int ListLength_SqList(SqList); //求顺序表L的长度
Status Destroy_SqList(SqList *); //销毁一张顺序表
void printlist_SqList(SqList); //输出顺序表
int FindMax(SqList); //找最大数
int FindUMin(SqList); //返回数组中未出现的最小正整数
void input(SqList *); //输入操作
//****main****
int main() {
int UMin; //未出现最小正整数
SqList La;
InitList_SqList(&La);
input(&La); //根据输入创建La
printf("Original SqList: ");
printlist_SqList(La); //输出原顺序表
UMin = FindUMin(La); //找出未出现最小正整数
printf("Number is: %d",UMin); //输出结果
return 0;
}//main
void input(SqList *La){ //输入操作
int l; //用户想要创建的列表长度
ElemType e;
printf("How long a sequence list do you want to create?\n");
scanf("%d",&l);
printf("Please enter some integers to fill the sequence List:\n");
for(int i = 1; i<=l; i++) { //挨个把用户输入存入顺序表
scanf("%d",&e.number);
ListInsert_SqList(La,i,e);
}
} //input
Status InitList_SqList(SqList *L) { //构造一个空顺序表L
L->elem=(ElemType *)malloc(LIST_INIT_SIZE*sizeof(ElemType));//分配内存
if(!L->elem)
exit(OVERFLOW);
L->length = 0;
L->listsize = LIST_INIT_SIZE;
return OK;
} //InitList_SqList
Status ListInsert_SqList(SqList *L, int i, ElemType e) { //在顺序表L的第i个元素前插入新元素e
ElemType *newbase, *p, *q;
if(i<1 || i>L->length+1)
return ERROR; //插入位置不合法
if(L->length >= L->listsize) { //当前存储空间已满,增加分配
newbase = (ElemType *)realloc(L->elem, (L->listsize + LISTINCREMENT)*sizeof(ElemType));
if(!newbase)
return ERROR; //存储分配失败
L->elem = newbase; //新基址
L->listsize += LISTINCREMENT; //增加存储容量
}
q = &(L->elem[i-1]); //q指向插入位置
for(p = &L->elem[L->length - 1]; p>=q; --p)
*(p+1) = *p; //插入位置之后的数据元素右移
*q = e; //插入e
L->length++;
return OK;
} //ListInsert_SqList
int ListLength_SqList(SqList L) { //求顺序表L的长度
return L.length;
} //ListLength_SqList;
Status Destroy_SqList(SqList *L) { //销毁一张顺序表
free(L);
return OK;
} //Destroy_SqList
void printlist_SqList(SqList L) { //输出顺序表
int i;
for(i = 0; i<L.length; i++)
printf("%d ", L.elem[i].number);
printf("\n");
} //printlist_SqList;
int FindUMin(SqList L) { //返回数组中未出现的最小正整数
int max = 0;FindMax(L);
if(max<1){
return 1;
}else {
for(int i=0;i<L.length;i++){
List[L.elem[i].number]++;
}
for(int i=1;i<max;i++){
if(List[i]==0){
return i;
}
}
return max+1;
}
} //FindUMin
int FindMax(SqList L){ //找最大数
int max = L.elem[0].number;
for(int i=0;i<L.length;i++){
if(max<L.elem[i].number){
max = L.elem[i].number;
}
}
return max;
}//FindMax
总结:
这道题还是要懂一点脑筋的↖(^ω^)↗