[LeetCode] Maximum Gap 最大间隙问题

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);
    }

}
                                               
                                            

运行结果如下:

                                    
                              
test.txt:
5
2.3 3.1 7.5 1.5 6.3
                             
程序运行后count,low和high数组的值如下:
index01234
count02102
low7.51.53.17.56.3
high1.52.33.11.57.5
 
 
 
 
 
 
                                   
                                   
test1.txt:
5
2.3 3.0 7.5 1.5 6.3
                                    
程序运行后count,low和high数组的值如下:
index01234
count02102
low7.51.53.07.56.3
high1.52.33.01.57.5
 
 
 
 
 
 
                                     
                                        
test2.txt:
5
4.5 3.0 7.5 1.5 6.0
                       
程序运行后count,low和high数组的值如下:
index01234
count01112
low7.51.53.04.56.0
high1.51.53.04.57.5
 
 
 
 
 
 
                                   
                                             
test3.txt:
5
2.3 3.1 10.0 1.5 6.3
                                         
程序运行后count,low和high数组的值如下:
index01234
count03011
low10.01.510.06.310.0
high1.53.13.06.310.0
 
 
 
 
 
 
                                                                         
                                                
test.4.txt:
15
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
                                                    
程序运行后count,low和high数组的值如下:
index01234567891011121314
count032020210011102
low25.31.03.125.36.325.310.011.725.325.318.319.921.425.324.1
high1.02.33.41.06.51.010.211.71.01.018.319.921.41.025.3
 
 
 
 
 
 
                                                             
                                                

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值