[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数组的值如下:
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
 
 
 
 
 
 
                                   
                                   
test1.txt:
5
2.3 3.0 7.5 1.5 6.3
                                    
程序运行后count,low和high数组的值如下:
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
 
 
 
 
 
 
                                     
                                        
test2.txt:
5
4.5 3.0 7.5 1.5 6.0
                       
程序运行后count,low和high数组的值如下:
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
 
 
 
 
 
 
                                   
                                             
test3.txt:
5
2.3 3.1 10.0 1.5 6.3
                                         
程序运行后count,low和high数组的值如下:
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
 
 
 
 
 
 
                                                                         
                                                
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数组的值如下:
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
 
 
 
 
 
 
                                                             
                                                
[LeetCode] Maximum Gap 最大间隙问题_第1张图片

你可能感兴趣的:(LeetCode)