Given an unsorted array, find the maximum difference between the successive elements in its sorted form. Try to solve it in linear time/space. Return 0 if the array contains less than 2 elements. You may assume all elements in the array are non-negative integers and fit in the 32-bit signed integer range.
问题描述:
给定n个实数x1,x2,...,xn,求这n个实数在实轴上相邻2个数之间的最大差值,要求设计线性的时间算法
算法思想:
最直接的方法就是对n个数据进行排序,然后一边扫描即可确定相邻的最大间隙。普通的排序方法不满足线性时间的要求。故采取桶排序的方法:
1. 找到n个数据中最大和最小数据maxx和minx;
2. 用n-2个点等分区间[minx,maxx],即将[minx,maxx]等分为n-1个区间(前闭后开区间),将这些区间看做桶,编号为1,2,...,n-2,n-1,且桶i的上界和桶i+1的下届相同,即每个桶的大小相同;
每个桶的大小为: dblAvrGap=(maxx-minx)/(n-1)
实际上,这些桶的边界就构成了一个等差数列(首项为minx,公差d=dblAvrGap),且人为将minx放入第1个桶,将maxx放入第n-1个桶。
编程实现中,用以下数据结果存放有关桶的数据:
int *count=new int[n]; //实际分到每个桶的数据个数
double *low=new double[n]; //实际分到每个桶的最小数据
double *high=new double[n]; //实际分到每个桶的最大数据
3. 将n个数放入n-1个桶中:
3.1 按如下规则将x[i]分配到某个桶(编号index)中: index=int((x[i]-minx)/dblAvrGap)+1;
若x[i]=minx,则被分到第1个桶中(minx即为桶1的下界);
若x[i]=桶j的下界(也是桶j-1的上界),则被分到桶j中(j>=1);
若x[i]=maxx,则被分到桶n中(max为桶n的下界桶n-1的上界),但没有桶n,解决办法:
可人为将其移入桶n-1中或者再加一个桶,这并不影响求其最大间隙;
3.2 调整分到该桶的最大最小数据;
4. 求最大间隙:
除最大最小数据maxx和minx以外的n-2个数据被放入n-1个桶中,由抽屉原理可知至少有一个桶是空的;
又因每个桶的大小相同,所以最大间隙不会在同一桶中出现;
一定是某个桶的上界(dblHigh)和其后某个桶的下界(dblLow)之间隙,且该两桶之间的桶(即编号在该两桶编号之间的桶)一定是空桶;
即最大间隙在桶i的上界和桶j的下界之间产生(j>=i+1);
下面的代码解决了整数数列最大间隙问题(通过了OJ的测试),来自http://blog.csdn.net/u012162613/article/details/41936569:
class Solution {
public:
int maximumGap(vector<int> &num) {
if (num.size() < 2) return 0;
//遍历一遍,找出最大最小值
int maxNum = num[0];
int minNum = num[0];
for (int i : num) {
maxNum=max(maxNum,i);
minNum=min(minNum,i);
}
// 每个桶的长度len,向上取整所以加+
int len = (maxNum - minNum) / num.size() + 1;
//桶的个数:(maxNum - minNum) / len + 1,每个桶里面存储属于该桶的最大值和最小值即可,注意这里的最大最小值是局部的
vector<vector<int>> buckets((maxNum - minNum) / len + 1);
for (int x : num) {
int i = (x - minNum) / len;
if (buckets[i].empty()) {
buckets[i].reserve(2);
buckets[i].push_back(x);
buckets[i].push_back(x);
} else {
if (x < buckets[i][0]) buckets[i][0] = x;
if (x > buckets[i][1]) buckets[i][1] = x;
}
}
//gap的计算,For each non-empty buckets p, find the next non-empty buckets q, return min( q.min - p.max )
int gap = 0;
int prev = 0;
for (int i = 1; i < buckets.size(); i++) {
if (buckets[i].empty()) continue;
gap = max(gap, buckets[i][0] - buckets[prev][1]);
prev = i;
}
return gap;
}
};
另外的代码如下:
输入:
文件格式:
n
x1 x2 ... xn
输出:maxgap(最大间隙)
* 最大间隙问题:给定n个实数x1,x2,...,xn,求这n个实数在实轴上相邻2个数之间
* 的最大差值,要求设计线性的时间算法
************************************************************************/
#include < iostream >
#define FILENAMELENGTH 50
// 声明函数
template < class T >
int indexofmin( int n,T * x);
template < class T >
int indexofmax( int n,T * x);
// 类
class CMaxGap
{
public:
int m_nCount; //数据的个数
double m_dblMaxGap; //最大间隙
double *m_dblNumber;//存放数据的数组
CMaxGap(const char *filename);
~CMaxGap();
double GetMaxGap(int n,double *x);
void Display();
} ;
// 读入数据
CMaxGap::CMaxGap( const char * filename)
{
FILE *fp=fopen(filename,"r");
if(fp==NULL)
{
printf("can not open file!");
exit(0);
}
//读入数据个数
fscanf(fp,"%d",&m_nCount);
m_dblNumber=new double[m_nCount];
//读入每个具体的数据
for(int i=0;i<m_nCount;i++)
fscanf(fp,"%lf",&m_dblNumber[i]);
m_dblMaxGap=0;
fclose(fp);
}
CMaxGap:: ~ CMaxGap()
{
delete[] m_dblNumber;
m_dblNumber=NULL;
}
// 获取n个数据的最大间隙,存放在以x为开始地址的单元中,数据下标为0,1,...,n-1
double CMaxGap::GetMaxGap( int n, double * x)
{
//找到最大最小数据,考虑到浮点型数据在传递过程中可能会有微小的变化
//故采取取其下标的方式,在直接读取
int minindex=indexofmin(n,x);
int maxindex=indexofmax(n,x);
double minx=x[minindex];
double maxx=x[maxindex];
//用n-2个点等分区间[minx,maxx],产生n-1个桶,桶编号1,2,...,n-2,n-1
//且桶i的上界和桶i+1的下届相同
double dblAvrGap=(maxx-minx)/(n-1); //每个等分区间大小,即每个桶的大小
int *count=new int[n]; //实际分到每个桶的数据个数
double *low=new double[n]; //实际分到每个桶的最小数据
double *high=new double[n]; //实际分到每个桶的最大数据
//初始化桶
for(int i=0;i<n;i++)
{
count[i]=0;
low[i]=maxx;
high[i]=minx;
}
int index; //桶编号
//将n个数放入n-1个桶中
for(int i=0;i<n;i++)
{
//按如下规则将x[i]分配到某个桶(编号index)中
//若x[i]=minx,则被分到第1个桶中(minx即为桶1的下界)
//若x[i]=桶j的下界(也是桶j-1的上界),则按如下公式被分到桶j中(j>=1)
index=int((x[i]-minx)/dblAvrGap)+1;
//若x[i]=maxx,则被分到桶n中(max为桶n的下界桶n-1的上界)
// 但没有桶n,此时可人为将其移入桶n-1中,或者再加一个桶
//该步操作不影响下面的求最大间隙
if(index==n)
index--;
count[index]++;
//调整分到该桶的最大最小数据
if(x[i]<low[index])
low[index]=x[i];
if(x[i]>high[index])
high[index]=x[i];
}
//除最大最小数据maxx和minx以外的n-2个数据被放入n-1个桶中
// 由抽屉原理可知至少有一个桶是空的
//又因每个桶的大小相同,所以最大间隙不会在同一桶中出现
// 一定是某个桶的上界(dblHigh)和其后某个桶的下界(dblLow)之间隙
// 注意:该两桶之间的桶(即编号在该两桶编号之间的桶)一定是空桶
// 即最大间隙在桶i的上界和桶j的下界之间产生(j>=i+1)
double dblMaxGap=0,dblHigh=high[1],dblTempGap;
for(int i=2;i<n;i++)
{
if(count[i]) //该桶非空才计算
{
dblTempGap=low[i]-dblHigh;
if(dblMaxGap<dblTempGap)
dblMaxGap=dblTempGap;
dblHigh=high[i];
}
}
//释放
delete[] count;
count=NULL;
delete[] low;
low=NULL;
delete[] high;
high=NULL;
m_dblMaxGap=dblMaxGap;
return dblMaxGap;
}
void CMaxGap::Display()
{
printf(" %d numbers: ",m_nCount);
for(int i=0;i<m_nCount;i++)
{
printf("%.2f ",m_dblNumber[i]);
}
printf(" the max gap is: %.2f ",m_dblMaxGap);
}
// 求数组中最小数据的下标
template < class T >
int indexofmin( int n,T * x)
{
int index;
T temp=x[0];
for(int i=1;i<n;i++)
{
if(x[i]<temp)
{
temp=x[i];
index=i;
}
}
return index;
}
// 求数组中最大数据的下标
template < class T >
int indexofmax( int n,T * x)
{
int index;
T temp=x[0];
for(int i=1;i<n;i++)
{
if(x[i]>temp)
{
temp=x[i];
index=i;
}
}
return index;
}
// 显示菜单
void show_menu()
{
printf("--------------------------------------------- ");
printf("input command to test the program ");
printf(" i or I : input filename to test ");
printf(" q or Q : quit ");
printf("--------------------------------------------- ");
printf("$ input command >");
}
void main()
{
char sinput[10];
char sfilename[FILENAMELENGTH];
show_menu();
scanf("%s",sinput);
while(stricmp(sinput,"q")!=0)
{
if(stricmp(sinput,"i")==0)
{
printf(" please input a filename:");
scanf("%s",sfilename);
//求文件中数据的最大间隙
CMaxGap gap(sfilename);
double dblMaxGap=gap.GetMaxGap(gap.m_nCount,gap.m_dblNumber);
gap.Display();
}
//输入命令
printf("$ input command >");
scanf("%s",sinput);
}
}
运行结果如下:
2.3 3.1 7.5 1.5 6.3
index | 0 | 1 | 2 | 3 | 4 |
count | 0 | 2 | 1 | 0 | 2 |
low | 7.5 | 1.5 | 3.1 | 7.5 | 6.3 |
high | 1.5 | 2.3 | 3.1 | 1.5 | 7.5 |
2.3 3.0 7.5 1.5 6.3
index | 0 | 1 | 2 | 3 | 4 |
count | 0 | 2 | 1 | 0 | 2 |
low | 7.5 | 1.5 | 3.0 | 7.5 | 6.3 |
high | 1.5 | 2.3 | 3.0 | 1.5 | 7.5 |
4.5 3.0 7.5 1.5 6.0
index | 0 | 1 | 2 | 3 | 4 |
count | 0 | 1 | 1 | 1 | 2 |
low | 7.5 | 1.5 | 3.0 | 4.5 | 6.0 |
high | 1.5 | 1.5 | 3.0 | 4.5 | 7.5 |
2.3 3.1 10.0 1.5 6.3
index | 0 | 1 | 2 | 3 | 4 |
count | 0 | 3 | 0 | 1 | 1 |
low | 10.0 | 1.5 | 10.0 | 6.3 | 10.0 |
high | 1.5 | 3.1 | 3.0 | 6.3 | 10.0 |
2.3 3.1 10.0 1.5 6.3 10.2 1.0 25.3 3.4 6.5 21.4 18.3 11.7 24.1 19.9
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
count | 0 | 3 | 2 | 0 | 2 | 0 | 2 | 1 | 0 | 0 | 1 | 1 | 1 | 0 | 2 |
low | 25.3 | 1.0 | 3.1 | 25.3 | 6.3 | 25.3 | 10.0 | 11.7 | 25.3 | 25.3 | 18.3 | 19.9 | 21.4 | 25.3 | 24.1 |
high | 1.0 | 2.3 | 3.4 | 1.0 | 6.5 | 1.0 | 10.2 | 11.7 | 1.0 | 1.0 | 18.3 | 19.9 | 21.4 | 1.0 | 25.3 |