#P2848. 第1题-合并重叠和连续IP区间
-
1000ms
Tried: 1072
Accepted: 274
Difficulty: 4
所属公司 :
华为
时间 :2025年4月16日-暑期实习(留学生)
-
算法标签>排序算法
第1题-合并重叠和连续IP区间
题目描述
给定多个 IP 区间,其中每个区间表示为 [start_ip,end_ip],请合并所有重叠和连续的 IP 区间,并返回一个 IP 区间顺序集合。
区间连续要求按照 start_ip 从小到大升序排序。
解题思路
-
IP ↔ 整数
-
将每个 IPv4 地址转换为一个 32 位整数,便于排序和相邻判断。
-
转换公式:
x = A×2^24 + B×2^16 + C×2^8 + D其中 IP 为 “A.B.C.D”。
-
-
排序
- 对所有区间按“起始整数”升序排序;若起始相同,则按“结束整数”升序。
-
线性合并
- 准备一个空列表
merged。 - 依次遍历排序后的每个区间
[cur_start, cur_end]:- 如果
merged为空,直接将当前区间加入; - 否则取
last = merged[最后一个]:- 若
cur_start > last.end + 1,说明二者既不重叠也不相邻——将[cur_start, cur_end]追加到merged; - 否则,说明有重叠或相邻——更新
last.end = max(last.end, cur_end)。
- 若
- 如果
- 准备一个空列表
-
结果输出
- 遍历
merged中的每个整型区间,转换回 “A.B.C.D” 格式,按[start_ip,end_ip]打印,中间用空格或换行分隔。
- 遍历
完整代码
cpp
#include <bits/stdc++.h>
using namespace std;
// 将IPv4地址转换为整数,使用 long long 类型以避免溢出
long long ip_to_int(const string &ip) {
long long a, b, c, d;
char dot;
istringstream iss(ip);
iss >> a >> dot >> b >> dot >> c >> dot >> d;
return (a << 24) | (b << 16) | (c << 8) | d;
}
// 将整数转换回IPv4地址格式
string int_to_ip(long long x) {
return to_string((x >> 24) & 0xFF) + "." +
to_string((x >> 16) & 0xFF) + "." +
to_string((x >> 8) & 0xFF) + "." +
to_string(x & 0xFF);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N;
if (!(cin >> N)) return 0;
vector<pair<long long, long long>> intervals;
intervals.reserve(N);
string token;
for (int i = 0; i < N; ++i) {
cin >> token; // 格式: [start_ip,end_ip]
token = token.substr(1, token.size() - 2);
size_t comma = token.find(',');
string start_ip = token.substr(0, comma);
string end_ip = token.substr(comma + 1);
long long s = ip_to_int(start_ip);
long long e = ip_to_int(end_ip);
intervals.emplace_back(s, e);
}
// 按起始IP排序
sort(intervals.begin(), intervals.end());
// 合并重叠或连续的区间
vector<pair<long long, long long>> merged;
for (auto &iv : intervals) {
if (merged.empty() || iv.first > merged.back().second + 1) {
merged.push_back(iv);
} else {
merged.back().second = max(merged.back().second, iv.second);
}
}
// 输出结果,格式 [start_ip,end_ip] 空格分隔
for (size_t i = 0; i < merged.size(); ++i) {
cout << "[" << int_to_ip(merged[i].first)
<< "," << int_to_ip(merged[i].second) << "]";
if (i + 1 < merged.size()) cout << ' ';
}
return 0;
}
python
import sys
def ip_to_int(ip: str) -> int:
"""
将IPv4地址从点分十进制格式转换为整数
"""
a, b, c, d = map(int, ip.split('.'))
return (a << 24) | (b << 16) | (c << 8) | d
def int_to_ip(num: int) -> str:
"""
将整数转换回点分十进制格式的IPv4地址
"""
return '.'.join(str((num >> (8 * i)) & 255) for i in range(3, -1, -1))
def merge_ip_intervals(intervals):
"""
合并重叠和连续的IP地址区间
参数:
intervals: List of tuples [(start_int, end_int), ...]
返回:
merged: List of merged intervals as tuples
"""
# 按起始地址排序
intervals.sort(key=lambda x: x[0])
merged = []
for start, end in intervals:
if not merged:
merged.append([start, end])
else:
prev_start, prev_end = merged[-1]
# 如果有重叠或连续(prev_end + 1 >= start)
if start <= prev_end + 1:
merged[-1][1] = max(prev_end, end)
else:
merged.append([start, end])
return merged
def main():
data = sys.stdin.read().strip().split() # 读取输入并按空白分割
n = int(data[0])
raw_intervals = data[1:1+n]
intervals = []
for item in raw_intervals:
# 去掉方括号和逗号,分割开始和结束IP
item = item.strip()
# 格式如 [192.168.1.1,192.168.1.3]
start_ip, end_ip = item.strip('[]').split(',')
start_int = ip_to_int(start_ip)
end_int = ip_to_int(end_ip)
intervals.append((start_int, end_int))
merged = merge_ip_intervals(intervals)
# 输出合并后的区间,格式为 [start_ip,end_ip] 并用空格分隔
output = []
for start_int, end_int in merged:
output.append(f"[{int_to_ip(start_int)},{int_to_ip(end_int)}]")
print(' '.join(output))
if __name__ == "__main__":
main()
java
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.*;
public class Main {
// 将 IPv4 地址转换为 32 位整数并返回 long
private static long ipToLong(String ip) {
String[] parts = ip.split("\\.");
long A = Long.parseLong(parts[0]);
long B = Long.parseLong(parts[1]);
long C = Long.parseLong(parts[2]);
long D = Long.parseLong(parts[3]);
return (A << 24) | (B << 16) | (C << 8) | D;
}
// 将 long 整数转换回 IPv4 字符串
private static String longToIp(long x) {
long A = (x >> 24) & 0xFF;
long B = (x >> 16) & 0xFF;
long C = (x >> 8) & 0xFF;
long D = x & 0xFF;
return A + "." + B + "." + C + "." + D;
}
// 合并重叠或相邻的区间
private static List<long[]> mergeIntervals(List<long[]> intervals) {
// 按 start 升序排序
intervals.sort(Comparator.comparingLong(a -> a[0]));
List<long[]> merged = new ArrayList<>();
for (long[] iv : intervals) {
if (merged.isEmpty() || iv[0] > merged.get(merged.size() - 1)[1] + 1) {
// 不重叠也不相邻,添加新区间
merged.add(new long[]{ iv[0], iv[1] });
} else {
// 重叠或相邻,则扩展末端
long[] last = merged.get(merged.size() - 1);
last[1] = Math.max(last[1], iv[1]);
}
}
return merged;
}
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 读取区间个数
int N = Integer.parseInt(br.readLine().trim());
List<long[]> intervals = new ArrayList<>(N);
for (int i = 0; i < N; i++) {
String line = br.readLine().trim();
// 期望格式如 "[192.168.1.1,192.168.1.3]"
line = line.substring(1, line.length() - 1);
String[] parts = line.split(",");
String sIp = parts[0];
String eIp = parts[1];
long s = ipToLong(sIp);
long e = ipToLong(eIp);
intervals.add(new long[]{ s, e });
}
// 合并
List<long[]> merged = mergeIntervals(intervals);
// 输出
StringBuilder sb = new StringBuilder();
for (int i = 0; i < merged.size(); i++) {
long[] iv = merged.get(i);
sb.append("[")
.append(longToIp(iv[0]))
.append(",")
.append(longToIp(iv[1]))
.append("]");
if (i + 1 < merged.size()) {
sb.append(" ");
}
}
System.out.println(sb.toString());
}
}
题目内容
给定多个 IP 区间,其中每个区间表示为 [start_ip,end_ip],请合并所有重叠和连续的 IP 区间,并返回一个 IP 区间顺序集合。
区间连续要求按照 start_ip 从小到大升序排序。
输入描述
1.第一行为区间个数 N ,有效范围为 [1,100]
2.输入 N 个 IP 地址区间,每个区间的格式为 [start_ip,end_ip] (中间用空格分隔),其中 start_ip 和 end_ip 为合法的 IPv4 地址点分十进制格式,即 A,B,C,D ,其中 A、B、C 和 D 的取值范围为 [0,255] 。
3.IP 地址大小的比较,是按照 A、B、C 和 D 的顺序进行比较。
输出描述
输出合并且排序好的 M 个区间。每个区间的格式为 [start_ip,end_ip] , 且用空格分隔。
样例1
输入
3
[192.168.1.1,192.168.1.3]
[192.168.1.2,192.168.1.3]
[192.168.1.4,192.168.1.5]
输出
[192.168.1.1,192.168.1.5]
说明
- 区间 [192.168.1.1,192.168.1.3] 和区间 [192.168.1.2,192.168.1.3] 的重叠部分是 [192.168.1.2,192.168.1.3]。
因此可以合并为 [192.168.1.1,192.168.1.3]。
- 区间 [192.168.1.1,192.168.1.3] 和区间 [192.168.1.4,192.168.1.5] 为连续 IP 。
因此也可以合并为 [192.168.1.1,192.168.1.5]。
样例2
输入
3
[192.168.1.5,192.168.1.8]
[192.168.1.6,192.168.1.7]
[192.168.1.2,192.168.1.3]
输出
[192.168.1.2,192.168.1.3] [192.168.1.5,192.168.1.8]
说明
区间 [192.168.1.5,192.168.1.8] 和区间 B [192.168.1.6,192.168.1.7] 的重叠部分是 [192.168.1.6,192.168.1.7]。
因此可以合并为 [192.168.1.5,192.168.1.8],而区间 C [192.168.1.2,192.168.1.3] 与 [192.168.1.5,192.168.1.8] 既不重叠,也不连续。
因此输出为 [193.168.1.2,193.168.1.3][193.168.1.5,193.168.1.8]