每天一到算法题--重叠区间大小

题目描述

请编写程序,找出下面 “ 输入数据及格式 ” 中所描述的输入数据文件中最大重叠区间的大小。

对一个正整数 n ,如果 n 在数据文件中某行的两个正整数(假设为 A 和 B )之间,即 A<=n<=B 或 A>=n>=B ,则 n 属于该行;如果 n 同时属于行 i 和 j ,则 i 和 j 有重叠区间;重叠区间的大小是同时属于行 i 和 j 的整数个数。
例如,行(10 20 )和( 12 25 )的重叠区间为 [12 20] ,其大小为 9 ;行( 20 10 )和( 12 18 )的重叠区间为 [10 12] ,其大小为 3 ;行 (20 10) 和( 20 30 )的重叠区间大小为 1 。

输入数据:程序读入已被命名为 input.txt 的输入数据文本文件,该文件的行数在 1 到 1,000,000 之间,每行有用一个空格分隔的 2 个正整数,这 2 个正整数的大小次序随机,每个数都在 1 和 2^32-1 之间。(为便于调试,您可下载测试 input.txt 文件,实际运行时我们会使用不同内容的输入文件。)

输出数据:在标准输出上打印出输入数据文件中最大重叠区间的大小,如果所有行都没有重叠区间,则输出 0 。

评分标准:程序输出结果必须正确,内存使用必须不超过 256MB ,程序的执行时间越快越好。


算法思路:

采用递推的方式。

先对所有区间以起始端点为基础进行排序,得到一个排序后的区间序列。然后对每一个区间考察后面可能与其重叠的区间。

具体方式为:

设当前的区间为c[a, b], 紧邻的下一个区间为n[a,b].

  • 当 c.b < n.a时, n,c没有重叠区间。又由于区间是按照起始点递增排序,所以后续的区间也不会与c有重叠区间。
  • 当 c.b >= n.a 时候,n, c有重叠区间。大小为 min{c.b-n.a, n.b-n.a}
  • 将得到的当前覆盖长度与保存的max做比较,保存大者。
  • 如此对所有的区间都进行这个操作。值得注意的是,当 c.b > n.b时候,n区间被包含在c区间中。在后续的遍历中就无需考虑n这个区间了。小小的技巧在特殊情况下(比如很多区间嵌套),会很快提高运行速度。


代码:

#include <iostream>
#include <fstream>
#include <algorithm>
#include <vector>

using namespace std;

// find the longest overlap interval

class Interval {
      public :
             int first;
             int last;
      public: 
              Interval(int first, int last);
};

Interval::Interval(int first, int last)
{
        this->first = first;
        this->last = last;
}

bool intervalCompare(Interval a, Interval b)
{
     return a.first < b.first;
}


void swap(int & a, int & b)
{
     int temp;
     temp = a;
     a = b;
     b = temp;
}

int max(int a, int b)
{
    return a > b? a : b;
}

int min(int a, int b)
{
    return a < b? a : b;
}

void print(vector<Interval> * v)
{
     vector<Interval>::iterator it;
     for (it=v->begin(); it!=v->end(); ++it)
            cout << "[" << it->first << "," << it->last<<"]\t";
     cout << endl;
     
}

int main()
{
    ifstream in("c:/input.txt");
    vector<Interval> * allIntervals = new vector<Interval>();
    vector<Interval>::iterator it;
    int first;
    int last;
    while(in >> first >> last)
    {
              if(first > last)
                   swap(first, last);    
              Interval *a = new Interval(first, last);
              allIntervals->push_back(*a);              
    }
    
    cout << "input is : " << endl;
    print(allIntervals);
 
    sort(allIntervals->begin(), allIntervals->end(), intervalCompare);
    cout << "after sorted,  is : " << endl;
    print(allIntervals);    
    
    
    //find the longest overlap
    //µ±Ç°µÄinterval c[a,b],½ô½ÓÆäºóµÄinterva n[a,b] 
    //µ± c.b < n.a ʱ£¬Çø¼äûÓи²¸Ç
    //µ± c.b >= n.a ʱ£¬µ±Ç°µÄÇø¼ä¸²¸ÇΪ max(c.b-n.a, n.b-n.a). 
     int maxOverlapLength = 0;
     int length = allIntervals->size();
     for(int i = 0; i < length-1; i++)
     {
             Interval cur = (*allIntervals)[i];       
             int j = i+1;
             Interval next = (*allIntervals)[j];
             while(cur.last >= next.first)
             {
                        int m = min(cur.last-next.first, next.last-next.first);
                        maxOverlapLength = max(m, maxOverlapLength);
                        j = j+1;
                        next = (*allIntervals)[j];
                        if(cur.last >= next.last)
                        {
                                    i++;
                        }
             }
     }
     cout << "max overlap length is : " << maxOverlapLength << endl;

    system("pause");
    return 0;
}

讨论:

这里采用的方式是将所有数据读入内存,此时,很有可能会有内存益处的情况。此时可以先遍历一边,将区间分成两部分/四部分,每一部分按照上面的方法给出最大重叠区间。然后在考虑跨越两个部分的边界情况。综合得到结果。


你可能感兴趣的:(每天一到算法题--重叠区间大小)