#P3061. VLAN资源池(100分)
-
1000ms
Tried: 130
Accepted: 48
Difficulty: 3
所属公司 :
华为od
-
算法标签>模拟
VLAN资源池(100分)
题面描述
VLAN(虚拟局域网)是一种对局域网设备进行逻辑划分的技术。为了标识不同的VLAN,引入了VLAN ID(取值范围为1-4094)的概念。
定义一个VLAN ID的资源池(以下简称VLAN资源池),资源池中连续的VLAN用“开始VLAN-结束VLAN”表示,不连续的用单个整数表示,所有的VLAN用英文逗号连接起来。
现在有一个VLAN资源池,业务需要从资源池中申请一个VLAN,需要你输出从VLAN资源池中移除申请的VLAN后的资源池。
思路
-
解析输入的VLAN资源池字符串:
- 使用逗号分割字符串,得到各个VLAN段。
- 对于每个段,判断是否为范围(含有“-”),如果是,则将范围内的所有VLAN加入集合;否则,将单个VLAN加入集合。
-
移除申请的VLAN:
- 检查申请的VLAN是否在集合中,如果在,则移除;否则,保持集合不变。
-
排序VLAN集合:
- 将集合中的VLAN按照升序排序。
-
重新格式化VLAN资源池字符串:
- 遍历排序后的VLAN集合,合并连续的VLAN为范围表示。
- 将结果用逗号连接成最终的字符串输出。
-
注意事项:
- 输入的VLAN资源池可能是乱序的,需先解析成集合并排序。
- 移除后的VLAN集合可能会分成多个连续段,需要正确合并。
代码分析
-
函数
split:- 用于将输入字符串按指定分隔符(逗号)拆分成多个子串。
-
函数
parseVLANPool:- 接受一个字符串形式的VLAN资源池,解析并返回一个包含所有VLAN的
set<int>集合。 - 对于每个子串,如果包含“-”,则解析为范围并加入集合;否则,直接加入单个VLAN。
- 接受一个字符串形式的VLAN资源池,解析并返回一个包含所有VLAN的
-
函数
formatVLANPool:- 接受一个排序后的
vector<int>集合,将其格式化为题目要求的字符串形式。 - 遍历VLAN集合,合并连续的VLAN为范围,单独的VLAN保持单个表示。
- 接受一个排序后的
-
主函数
main:- 读取输入的VLAN资源池字符串和要申请的VLAN。
- 调用
parseVLANPool解析资源池。 - 移除申请的VLAN(如果存在)。
- 使用
set的erase方法进行移除。
- 使用
- 将剩余的VLAN集合转换为排序后的
vector<int>。 - 调用
formatVLANPool格式化输出字符串。 - 输出结果。
cpp
#include <bits/stdc++.h>
using namespace std;
// 函数:将字符串按照指定分隔符分割
vector<string> split(const string &s, char delimiter) {
vector<string> tokens;
string token;
// 使用stringstream进行分割
stringstream ss(s);
while (getline(ss, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
// 函数:解析VLAN资源池字符串,返回一个包含所有VLAN的集合
set<int> parseVLANPool(const string &s) {
set<int> vlanSet;
vector<string> segments = split(s, ',');
for (const string &seg : segments) {
// 检查是否为范围
size_t dashPos = seg.find('-');
if (dashPos != string::npos) {
// 是范围,提取开始和结束
string startStr = seg.substr(0, dashPos);
string endStr = seg.substr(dashPos + 1);
// 转换为整数
int start = stoi(startStr);
int end = stoi(endStr);
// 确保start <= end
if (start > end) swap(start, end);
// 添加范围内所有VLAN
for (int i = start; i <= end; ++i) {
vlanSet.insert(i);
}
}
else {
// 是单个VLAN
int vlan = stoi(seg);
vlanSet.insert(vlan);
}
}
return vlanSet;
}
// 函数:将排序后的VLAN列表格式化为题目要求的字符串
string formatVLANPool(const vector<int> &vlans) {
if (vlans.empty()) return "";
string result;
int n = vlans.size();
int start = vlans[0];
int prev = vlans[0];
for (int i = 1; i < n; ++i) {
if (vlans[i] == prev + 1) {
// 连续
prev = vlans[i];
}
else {
// 不连续,记录前面的范围
if (start == prev) {
result += to_string(start) + ",";
}
else {
result += to_string(start) + "-" + to_string(prev) + ",";
}
// 更新start和prev
start = vlans[i];
prev = vlans[i];
}
}
// 处理最后一个范围
if (start == prev) {
result += to_string(start);
}
else {
result += to_string(start) + "-" + to_string(prev);
}
return result;
}
int main(){
string vlanPoolStr;
string applyVLANStr;
// 读取输入
getline(cin, vlanPoolStr);
getline(cin, applyVLANStr);
// 解析VLAN资源池
set<int> vlanSet = parseVLANPool(vlanPoolStr);
// 解析要申请的VLAN
int applyVLAN = stoi(applyVLANStr);
// 移除申请的VLAN
vlanSet.erase(applyVLAN);
// 将集合转换为排序的向量
vector<int> vlanList(vlanSet.begin(), vlanSet.end());
sort(vlanList.begin(), vlanList.end());
// 格式化输出
string output = formatVLANPool(vlanList);
cout << output;
return 0;
}
python
def split(s, delimiter):
"""将字符串按照指定分隔符分割"""
return s.split(delimiter)
def parse_vlan_pool(s):
"""解析 VLAN 资源池字符串,返回一个包含所有 VLAN 的集合"""
vlan_set = set()
segments = split(s, ',')
for seg in segments:
# 检查是否为范围
if '-' in seg:
start_str, end_str = seg.split('-')
start = int(start_str)
end = int(end_str)
# 确保 start <= end
if start > end:
start, end = end, start
# 添加范围内所有 VLAN
for i in range(start, end + 1):
vlan_set.add(i)
else:
# 是单个 VLAN
vlan_set.add(int(seg))
return vlan_set
def format_vlan_pool(vlans):
"""将排序后的 VLAN 列表格式化为题目要求的字符串"""
if not vlans:
return ""
result = []
sorted_vlans = sorted(vlans)
start = sorted_vlans[0]
prev = sorted_vlans[0]
for vlan in sorted_vlans[1:]:
if vlan == prev + 1:
# 连续
prev = vlan
else:
# 不连续,记录前面的范围
if start == prev:
result.append(str(start))
else:
result.append(f"{start}-{prev}")
# 更新 start 和 prev
start = vlan
prev = vlan
# 处理最后一个范围
if start == prev:
result.append(str(start))
else:
result.append(f"{start}-{prev}")
return ",".join(result)
def main():
# 读取输入
vlan_pool_str = input().strip()
apply_vlan_str = input().strip()
# 解析 VLAN 资源池
vlan_set = parse_vlan_pool(vlan_pool_str)
# 解析要申请的 VLAN
apply_vlan = int(apply_vlan_str)
# 移除申请的 VLAN
vlan_set.discard(apply_vlan)
# 格式化输出
output = format_vlan_pool(vlan_set)
print(output)
if __name__ == "__main__":
main()
java
import java.util.*;
public class VLANManager {
// 函数:将字符串按照指定分隔符分割
public static List<String> split(String s, char delimiter) {
return Arrays.asList(s.split(String.valueOf(delimiter)));
}
// 函数:解析 VLAN 资源池字符串,返回一个包含所有 VLAN 的集合
public static Set<Integer> parseVLANPool(String s) {
Set<Integer> vlanSet = new HashSet<>();
List<String> segments = split(s, ',');
for (String seg : segments) {
// 检查是否为范围
if (seg.contains("-")) {
String[] bounds = seg.split("-");
int start = Integer.parseInt(bounds[0]);
int end = Integer.parseInt(bounds[1]);
// 确保 start <= end
if (start > end) {
int temp = start;
start = end;
end = temp;
}
// 添加范围内所有 VLAN
for (int i = start; i <= end; i++) {
vlanSet.add(i);
}
} else {
// 是单个 VLAN
vlanSet.add(Integer.parseInt(seg));
}
}
return vlanSet;
}
// 函数:将排序后的 VLAN 列表格式化为题目要求的字符串
public static String formatVLANPool(List<Integer> vlans) {
if (vlans.isEmpty()) {
return "";
}
StringBuilder result = new StringBuilder();
Collections.sort(vlans);
int start = vlans.get(0);
int prev = vlans.get(0);
for (int i = 1; i < vlans.size(); i++) {
int vlan = vlans.get(i);
if (vlan == prev + 1) {
// 连续
prev = vlan;
} else {
// 不连续,记录前面的范围
if (start == prev) {
result.append(start).append(",");
} else {
result.append(start).append("-").append(prev).append(",");
}
// 更新 start 和 prev
start = vlan;
prev = vlan;
}
}
// 处理最后一个范围
if (start == prev) {
result.append(start);
} else {
result.append(start).append("-").append(prev);
}
return result.toString();
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// 读取输入
String vlanPoolStr = scanner.nextLine().trim();
String applyVLANStr = scanner.nextLine().trim();
// 解析 VLAN 资源池
Set<Integer> vlanSet = parseVLANPool(vlanPoolStr);
// 解析要申请的 VLAN
int applyVLAN = Integer.parseInt(applyVLANStr);
// 移除申请的 VLAN
vlanSet.remove(applyVLAN);
// 将集合转换为排序的列表
List<Integer> vlanList = new ArrayList<>(vlanSet);
// 格式化输出
String output = formatVLANPool(vlanList);
System.out.println(output);
scanner.close();
}
}
题目内容
VLAN是一种对局域网设备进行逻辑划分的技术,为了标识不同的VLAN,引入VLAN ID(1−4094)之间的整数)的概念。
定义一个VLAN ID的资源池(下称VLAN资源池),资源池中连续的VLAN用开始VLAN−结束VLAN表示,不连续的用单个整数表示,所有的VLAN用英文逗号连接起来。
现在有一个VLAN资源池,业务需要从资源池中申请一个VLAN,需要你输出从VLAN资源池中移除申请的VLAN后的资源池。
输入描述
第一行为字符串格式的VLAN资源池,第二行为业务要申请的VLAN,VLAN的取值范围为[1,4094]之间的整数。
输出描述
从输入VLAN资源池中移除申请的VLAN后字符串格式的VLAN资源池,输出要求满足题目描述中的格式,并且按照VLAN从小到大升序输出。
如果申请的VLAN不在原VLAN资源池内,输出原VLAN资源池升序排序后的字符串即可。
备注
输入VLAN资源池中VLAN的数量取值范围为[2−4094]间的整数,资源池中VLAN不重复且合法([1,4094]之间的整数),输入是乱序的。
示例1
输入
1-5
2
输出
1,3-5
说明
原VLAN资源池中有VLAN 1、2、3、4、5,从资源池中移除2后,剩下VLAN 1、3、4、5,按照题目描述格式并升序后的结果为1,3-5。
示例2
输入
20-21,15,18,30,5-10
15
输出
5-10,18,20-21,30
说明
原VLAN资源池中有VLAN 5、6、7、8、9、10、15、18、20、21、30,从资源池中移除15后,资源池中剩下的VLAN为 5、6、7、8、9、10、18、20、21、30,按照题目描述格式并升序后的结果为5-10,18,20-21,30。
示例3
输入
5,1-3
10
输出
1-3,5
说明
原VLAN资源池中有VLAN 1、2、3,5,申请的VLAN 10不在原资源池中,将原资源池按照题目描述格式并按升序排序后输出的结果为1-3,5。