首页 > 试题广场 >

IP段合并

[编程题]IP段合并
  • 热度指数:1464 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
一个数字段由首尾两个数字标识,表示一个自然数集合,
比如数字段[beg, end)表示从beg到end之间的所有自然数,
包含beg,但不包含end。

有若干个数字段,这些数字段之间可能有重叠,
怎么把这些数字段合并去重,用最少个数的数字段来表示。

合并前后,整个集合包含的数字不发生变化。



输入描述:
第一行为数字N,表示接下来有N个数字段(N<=100000)
第二行开始一共有N行,每行两个数字,分别表示一个数字段的beg和end
(beg和end为无符号32位整数)


输出描述:
合并去重后形成的数字段集合,按升序排列。
示例1

输入

4 
3 8
3 7
4 6
7 9

输出

3 9
import sys

def InputFunc():
    a = int(input())
    data = []
    for i in range(a):
        data.append(list(map(int, input().split())))
    return a, data

def main():
    n, data = InputFunc()
    result = []
    data = sorted(data)
    result.append(data[0])
    for i in range(1, len(data)):
        if (data[i][0] > result[-1][1]):  #不重叠
            result.append(data[i])
        else:
            result[-1][1] = max(result[-1][1], data[i][1])
    for value in result:
        print(value[0], value[1])


if __name__ == "__main__":
    main()
发表于 2019-07-31 17:41:37 回复(1)
区间合并问题,先按照区间的左右端点进行二次排序(升序)。将第一个区间先加入区间集,然后遍历后面的区间,每次判断是否要跟区间集中的最后一个区间进行合并。
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;

class Node {
    public int start;
    public int end;
    public Node(int start, int end){
        this.start = start;
        this.end = end;
    }
}

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(br.readLine());
        Node[] nodes = new Node[n];
        for(int i = 0; i < n; i++){
            String[] params = br.readLine().split(" ");
            nodes[i] = new Node(Integer.parseInt(params[0]), Integer.parseInt(params[1]));
        }
        Arrays.sort(nodes, (a, b) -> a.start != b.start? a.start - b.start: a.end - b.end);
        ArrayList<Node> intervals = new ArrayList<>();
        intervals.add(nodes[0]);
        // 合并区间
        for(int i = 1; i < n; i++){
            if(intervals.get(intervals.size() - 1).end >= nodes[i].start){
                // 前后有区间重叠,进行区间合并,只需要将区间右端点改成大的那个就行
                intervals.get(intervals.size() - 1).end = Math.max(intervals.get(intervals.size() - 1).end, nodes[i].end);
            }else{
                // 没有区间重叠,直接加入
                intervals.add(nodes[i]);
            }
        }
        for(Node node: intervals){
            System.out.println(node.start + " " + node.end);
        }
    }
}

发表于 2021-12-06 18:12:15 回复(0)

有点暴力的解法

#include <iostream>
using namespace std;

int main() {
    bool x[1000000] = {0};
    int N;
    cin >> N;
    int l, r;
    while(N--) {
        cin >> l >> r;
        for(int i = l; i < r; i++) {
            x[i] = 1;
        }
    }
    for(int i = 0; i < 1000000; i++) {
        if((i == 0 && x[i] == 1) || (x[i-1] == 0 && x[i] == 1)) {
            cout << i << " ";
        } else if(x[i-1] == 1 && x[i] == 0) {
            cout << i << endl;
        }
    }
}
发表于 2020-02-26 10:06:45 回复(2)
//先排序
//再合并
//AC100
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
bool cmp(pair<int, int> p1, pair<int, int>p2) {
    if (p1.first != p2.first)
        return p1.first < p2.first;
    else 
        return p1.second <= p2.second;
}
int main()
{
    int N;
    cin >> N;
    vector<pair<int, int>> data;
    vector<pair<int, int>> res;
    while (N--) {
        int tmp1, tmp2;
        cin >> tmp1;
        cin >> tmp2;
        data.push_back(make_pair(tmp1, tmp2));
    }
    sort(data.begin(), data.end(), cmp);

    res.push_back(data[0]);
    for (int i = 1; i < data.size(); i++) {
        pair<int,int> tmp=res.back();
        if (tmp.second < data[i].first) {
            res.push_back(data[i]);
        }
        else{
            res.pop_back();
            res.push_back(make_pair(tmp.first, max(data[i].second, tmp.second)));
        }
    }
    for (auto c : res) {
        cout << c.first << " " << c.second<<endl;
    }
}

发表于 2019-09-07 11:09:06 回复(1)
先把数据按照左值小的,右值大的排序,然后再遍历整个数组。如果两个值对(a,b),(c,d),如果a<=b
&&b>=d那么对于(a,b)来说,(c,d)就可以被合并,如果b<d那么就可以把b的值替换为d,把(a,b)更新为
(a,d),如果c>b那么就意味着一个区间不能表示(a,b)和(c,d),必须要用两个区间来表示。遍历
一遍数组就行了。

import java.util.*;

public class Main{
    static class Pair implements Comparable<Pair>{
        public int a;
        public int b;
        public Pair(int a,int b){
            this.a=a;
            this.b=b;
        }
        @Override
        public int compareTo(Pair p){
            if(a==p.a) return p.b-b;
            else return a-p.a;
        }
    }
    public static void main(String[] args){
           Scanner sc=new Scanner(System.in);
           int n=sc.nextInt();
           Pair[] ps=new Pair[n];
           for(int i=0;i<n;i++){
               int k=sc.nextInt();
               int l=sc.nextInt();
               ps[i]=new Pair(k,l);
           }
           Arrays.sort(ps);
           /*for(int i=0;i<n;i++){
               System.out.println(ps[i].a+" "+ps[i].b);
           }*/
            List<Pair> result=new ArrayList<>();
            Pair now=ps[0];
            for(int i=1;i<n;i++){
                if(now.a<=ps[i].a&&now.b>=ps[i].b){
                    continue;
                }else if(ps[i].a>now.b){
                    result.add(now);
                    now=ps[i];
                }
                 else now.b=ps[i].b;
            }
            result.add(now);
            for(Pair p:result){
           System.out.println(p.a+" "+p.b);
          }
           sc.close();
    }
    
}

发表于 2019-08-04 18:29:03 回复(0)
# coding=utf-8
import sys
lines = []
try:
    while True:
        values = sys.stdin.readlines()
        values = [list(map(int, v.split())) for v in values]

        if not values:
            print
            break
        alls = []
        for i in range(len(values)):
            for j in range(values[i][0], values[i][-1]):
                alls.append(j)
        res = list(set(alls))

        duns = []
        p1, p2 = 0, 0
        while p2 <= len(res) - 1:
            if res[p2] - res[p1] == p2-p1:
                if p1 == len(res)-1:
                    duns.append([res[p1], res[p1]+1])
                if p1 != p2 and p2 == len(res) -1:
                    duns.append([res[p1], res[p2]+1])
                p2 += 1
            else:
                duns.append([res[p1], res[p2-1]+1])
                p1 = p2

        for ans in duns:
            if len(ans)>1:
                print ans[0], ans[1]
            else:
                print ans[0]
        break
except:
    pass
只ac了70%  超内存了 。。。。
发表于 2019-07-29 23:11:05 回复(1)
int n;
    scanf("%d", &n);
    while(n > 100000)
    {
        printf("值过大,请重新输入\n");
        scanf("%d", &n);
    }
    // printf("%d\n", n);
    long int beg, end, temp;
    int i,j,s,k = 0;
    int arr[n][2];

    for(i = 0;i<n;i++)
    {
        scanf("%d %d", &beg, &end);
        if(beg > end)
        {
            temp = end;
            end = beg;
            beg = temp;
        }
        if(i == 0)
        {
            arr[0][0] = beg;
            arr[0][1] = end;
        }
        else
            for(k=j; k>=0;k--)
            {
                if(arr[k-1][0] >= beg && k > 0)
                {
                    arr[k][0] = arr[k-1][0];
                    arr[k][1] = arr[k-1][1];
                }
                else
                {
                    arr[k][0] = beg;
                    arr[k][1] = end;
                    break;
                }
               
            }
        j++;
        s = 0;
        for(k=1; k<j;k++)
        {
            if(arr[k][0] <= arr[s][1] && arr[k][1] > arr[s][1])
            {
                arr[s][1]=arr[k][1];
                for(int n=k; n<j;n++)
                {
                    arr[n][0]=arr[n+1][0];
                    arr[n][1]=arr[n+1][1];
                }
                j--;
                k--;
            }
            else if(arr[k][0] <= arr[s][1] && arr[k][1] <= arr[s][1])
            {
                for(int n=k; n<j;n++)
                {
                    arr[n][0]=arr[n+1][0];
                    arr[n][1]=arr[n+1][1];
                }
                j--;
                k--;
            }
            else if(arr[k][0] > arr[s][1])
            {
                s++;
            }
        }
       
    }

    for(int a=0; a<j;a++)
    {
        printf("%d ", arr[a][0]);
        printf("%d ", arr[a][1]);
        printf("\n");
    }
发表于 2022-09-08 23:05:10 回复(0)
package main

import (
	"bufio"
	"os"
	"strings"
    "sort"
    "strconv"
    "fmt"
)

func main() {
	inputReader := bufio.NewReader(os.Stdin)

    line0, _ := inputReader.ReadString('\n')
    line0 = strings.Replace(line0, "\n", "", -1)
    n, _ := strconv.Atoi(line0)
    nums := make([][2]int, n)

    for i := 0; i < n; i++ {
        line1, _ := inputReader.ReadString('\n')
        line1 = strings.Replace(line1, "\n", "", -1)
        lines1 := strings.Split(line1, " ")
        nums[i][0], _ = strconv.Atoi(lines1[0])
        nums[i][1], _ = strconv.Atoi(lines1[1])
    }
    sort.Slice(nums, func(i, j int) bool {
        return nums[i][0] < nums[j][0]
    })
    res:=[][]int{}
    start:=nums[0][0]
    end:=nums[0][1]
    for i:=1;i<n;i++{
        if nums[i][0]<=end{
            end=max(end,nums[i][1])
        }else{
            res=append(res,[]int{start,end})
            start=nums[i][0]
            end=nums[i][1]
        }
    }
    res=append(res,[]int{start,end})
    for _,v:=range res{
        fmt.Println(v[0],v[1])
    }
}
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

发表于 2022-09-01 15:24:15 回复(0)
#include<bits/stdc++.h>
using namespace std;
int d[100005];
int main()
{
    int n;
    int left=99999;
    int right=0;
    cin>>n;
    memset(d,0,sizeof(d));
    for(int i=0;i<n;i++){
        int l,r;
        cin>>l>>r;
        if(l>r) swap(l,r);
        d[l+1]++;
        d[r+1]--;
        left=min(left,l+1);
        right=max(right,r+1);
    }
    for(int i=1;i<=right;i++){
        d[i]+=d[i-1];
        if(d[i]>0&&d[i-1]==0) cout<<i-1<<" ";
        else if(d[i]==0&&d[i-1]>0) cout<<i-1<<endl;
    }
    return 0;
}

差分,O(N)
发表于 2020-09-28 23:03:19 回复(0)
process.stdin.resume();
process.stdin.setEncoding('ascii');
  
var input = "";
  
process.stdin.on('data', function (data) {
    input += data;
});
  
process.stdin.on('end', function () {
    var input_array = input.split("\n");
   //示例代码
    var len = input_array.length;
    var result = [];
    var len1 = Number(input_array[0])
    for(let i=1; i<len; i++){
        let first = Number(input_array[i].split(' ')[0])
        let second = Number(input_array[i].split(' ')[1])
        for(let i=first;i<second;i++){
            result.push(i)
        }
    }
    
    let newArr = Array.from(new Set(result)).sort((a, b) => a - b)
    let finalStr = `${newArr[0]}`
    for (let i = 1; i < newArr.length; i++) {
        if (newArr[i] != newArr[i - 1] + 1) {
            finalStr += (`${' ' + (newArr[i - 1] + 1)}\n${' ' + (newArr[i] + 1) - 1}`)
        }
    }
    console.log(`${finalStr} ${newArr[newArr.length - 1] + 1}`)
    return `${finalStr} ${newArr[newArr.length - 1] + 1}`
})


内存超了,我泪目了
发表于 2020-09-10 11:34:41 回复(0)
优先级队列做的........
#include<set>
(855)#include<map>
#include<iostream>
(720)#include<algorithm>
#include<vector>
(721)#include<string>
#include<queue>
using namespace std;
struct cmp {
    bool operator()(vector<int> &v1, vector<int>&v2) {
        return v1[0] > v2[0];
    }
};
vector < vector<int>> ff(priority_queue<vector<int>, vector<vector<int>>, cmp> &pq);
 
int main() {
    priority_queue<vector<int>, vector<vector<int>>, cmp> less;
    int N = 0;
    cin >> N;
    int x = 0, y = 0;
    for (int i = 0; i < N; ++i) {
        cin >> x >> y;
 
        less.push({ x,y });
    }
    vector < vector<int>> res = ff(less);
 
    for (auto &i : res) {
        for (auto j : i)
            cout << j << " ";
        cout << endl;
    }
 
     
    return 0;
}
vector < vector<int>> ff(priority_queue<vector<int>, vector<vector<int>>, cmp> &pq) {
 
    vector < vector<int>> res;
    auto t1 = pq.top(); pq.pop();
    while (!pq.empty()) {
        auto tmp = pq.top(); pq.pop();
 
        if (t1[1] >= tmp[0]) t1[1] = max({ t1[1],tmp[1] });
        else {
             
            res.push_back(t1);
            t1 = tmp;
        }
         
 
    }
    res.push_back(t1);
 
    return res;
}

发表于 2020-02-25 20:28:31 回复(0)
Python3
对区间的左值先排序,再合并
import sys

if __name__ == '__main__':
    N = int(sys.stdin.readline().strip())
    raw_input = []
    for line in sys.stdin:
        raw_input.append(list(map(int, line.split())))
    raw_input.sort(key=lambda x:x[0])
    res = [raw_input[0]]
    for value in raw_input:
        if value[0] <= res[-1][1]:
            res[-1][1] = max(res[-1][1], value[1])
        else:
            res.append(value)
    for interval in res:
        print('{} {}'.format(interval[0], interval[1]))


发表于 2019-09-02 19:40:04 回复(0)
#include <iostream>
#include <algorithm>
#include <vector>
#include <set>
using std::cout;
using std::cin;
using std::endl;
using std::vector;
using std::set;


typedef struct 
{
    size_t begg;
    size_t endd;
}set_t;


bool compare(const set_t & aa,const set_t & bb)
{
    if(aa.begg < bb.begg)
    {
        return true;
    }else
    {
        return false;
    }
}

//*///

//合并
void myMerge(const vector<set_t>  & mySet , vector<set_t> & res)
{
    size_t idx1=0,idx2=1;
    set_t tmp1;
    while(idx1 < mySet.size())
    {
        tmp1 = mySet[idx1];
        while(idx2 < mySet.size())
        {
            //如果有交集, 合并
            set_t tmp2 = mySet[idx2];
            if(tmp2.begg <= tmp1.endd)
            {
                if(tmp1.endd <= tmp2.endd)
                {
                    tmp1.endd = tmp2.endd;
                }
            }else  //没有交集,则tmp1独立
            {
                res.push_back(tmp1);
                idx1 = idx2;
                break;
            }
            idx2++;
        }
        if(idx2 == mySet.size())  //只有一种情况
        {
            res.push_back(tmp1);
            break;
        }
        idx2 = idx1+1;
    }

}


int main()
{

    long int N;
    vector<set_t>  inputSet;
    cin >> N;
    for(long int i =0;i<N;i++)
    {
        set_t tmpIn;
        cin >> tmpIn.begg >> tmpIn.endd;
        if(tmpIn.begg <= tmpIn.endd)  //舍弃无效输入
            inputSet.push_back(tmpIn);
    }

   sort(inputSet.begin(),inputSet.end(),compare);
    
    vector<set_t>   result;
    myMerge(inputSet,result);

    for(auto cc : result)
    {
        cout << cc.begg << " " << cc.endd << endl;
    }
    return 0;
}

使用vector ,输入结束后先排序一次,然后再对段进行合并,因为vector中的序列有序,合并的时候就很方便了。

发表于 2019-08-24 22:21:36 回复(0)