尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

华为OD机试真题 新系统 2026-08-05 JavaGoC 实现【IPv4等长子网划分与自动分配系统】

华为OD机试真题 新系统 2026-08-05 JavaGoC 实现【IPv4等长子网划分与自动分配系统】 目录题目思路Code题目题目内容某企业新申请到一个完整的 IPv4 主网段网络管理员需要根据各部门申报的最小主机需求数量制定子网划分方案。请编写程序根据主网段信息、部门数量以及各部门需求自动计算满足所有部门需求的最小主机数网段并按申请部门信息连续分配等长子网。输入描述第一行输入合法的 IPv4 主网段CIDR 格式为 IP地址/掩码位数例如 192.168.10.0/24。第二行输入正整数 N表示部门数量范围为 1 到 20。第三行输入 N 个整数表示 N 个部门各自的最小主机需求数。输出描述若分配可行输出 N 个 CIDR 字符串按升序排列字符串之间用英文逗号分隔。若输入网段非法、主机位不足 2 位或无法同时满足所有部门的主机数需求和子网数量需求则输出空内容。所有生成的子网掩码长度必须完全一致子网必须从主网段起始地址开始连续分配子网地址不能重叠。可用主机数公式为 2 的 h 次方减 2其中 h 等于 32 减掩码位数。样例 1输入192.168.1.0/24 3 10 20 50输出192.168.1.0/26,192.168.1.64/26,192.168.1.128/26说明最大需求为 50需要 6 位主机位子网掩码为 26原网段可划分 4 个等长子网足够分配 3 个部门。样例 2输入192.168.1.0/24 20 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100 100输出说明每个部门至少需要 100 个主机子网需要 7 位主机位原网段只能划分 2 个等长子网不足以分配 20 个部门。样例 3输入192.168.1.0/24 2 10 10输出192.168.1.0/28,192.168.1.16/28说明最大需求为 10需要 4 位主机位子网掩码为 28。思路整体思路所有部门使用等长子网因此先由最大主机需求决定每个子网至少要保留多少主机位再判断主网段能切出多少个这样的子网。第一步解析并校验 CIDR。IPv4 地址需要四段每段在 0 到 255 之间掩码需要留出至少 2 位主机位主网段起始地址需要和掩码对齐。第二步计算最大需求 maxNeed。找到最小的主机位 h使得 2 的 h 次方减 2 大于等于 maxNeed则等长子网掩码为 32 - h。第三步如果子网掩码小于主网段掩码说明单个子网比主网段还大无法分配。否则可划分子网数为 2 的 子网掩码减主网段掩码 次方若小于部门数量则无法分配。第四步可行时从主网段起始地址开始每次增加一个子网大小输出连续的 N 个 CIDR。复杂度分析解析和生成只与 N 成正比时间复杂度 O(N)空间复杂度 O(N)。Codeimport java.util.ArrayList; import java.util.List; import java.util.Scanner; public class Main { static Long parseIp(String text) { String[] parts text.split(\\.); if (parts.length ! 4) { return null; } long value 0; for (String part : parts) { // 每段都必须是纯数字避免 parseInt 接受题目不允许的格式。 if (!part.matches(\\d)) { return null; } int octet Integer.parseInt(part); // IPv4 每段只能落在 0 到 255越界就不是合法地址。 if (octet 0 || octet 255) { return null; } value value * 256 octet; } return value; } static String formatIp(long value) { // 按 8 位一段拆回点分十进制输出才能符合 CIDR 格式。 return ((value 24) 255) . ((value 16) 255) . ((value 8) 255) . (value 255); } static int hostBitsFor(int hostNeed) { int bits 0; // bits 是子网中留给主机编号的位数共能组合出 2^bits 个地址。 // 全 0 的网络地址和全 1 的广播地址不能分给主机所以可用数是 2^bits - 2。 while ((1L bits) - 2 hostNeed) { bits; } return bits; } static ListString solve(String cidr, int subnetCount, int[] hostNeeds) { ListString answer new ArrayList(); // CIDR 必须包含斜杠斜杠前是起始 IP斜杠后是原始掩码长度。 int slash cidr.indexOf(/); if (slash 0) { return answer; } String maskText cidr.substring(slash 1); if (!maskText.matches(\\d)) { return answer; } int originalMask Integer.parseInt(maskText); // /24 表示 32 位地址的前 24 位是固定网络号后 8 位用于网内主机。 if (originalMask 0 || originalMask 30) { return answer; } Long baseObject parseIp(cidr.substring(0, slash)); if (baseObject null) { return answer; } long base baseObject; int originalHostBits 32 - originalMask; // networkMask 的网络位为 1、主机位为 0。按位与会把 base 的主机位全部清零。 // 清零后仍等于 base才说明输入 IP 正好是网段起点而不是网段里的普通主机。 long networkMask 0xffffffffL ^ ((1L originalHostBits) - 1); // 输入的起始 IP 必须正好落在原网段边界上否则不能从它开始划分。 if ((base networkMask) ! base) { return answer; } int maxHostNeed 0; for (int need : hostNeeds) { maxHostNeed Math.max(maxHostNeed, need); } // 等长子网要满足所有需求所以统一子网大小由最大主机需求决定。 int subnetHostBits hostBitsFor(maxHostNeed); // 子网掩码 32 - 主机位数主机位越多单个子网容量越大。 int subnetMask 32 - subnetHostBits; if (subnetMask originalMask) { return answer; } // 新掩码每比原掩码多 1 位原网段就能多切一倍子网。 // 因而可切数量是 2^(新掩码-原掩码)不足 subnetCount 时无法分配。 if ((1L (subnetMask - originalMask)) subnetCount) { return answer; } long subnetSize 1L subnetHostBits; for (int i 0; i subnetCount; i) { // 等长划分下每个子网起点只需要按子网大小依次递增。 answer.add(formatIp(base i * subnetSize) / subnetMask); } // answer 为空表示输入非法或大网段容量不足调用方会自然输出空字符串。 return answer; } public static void main(String[] args) { Scanner scanner new Scanner(System.in); String cidr scanner.nextLine().trim(); int subnetCount Integer.parseInt(scanner.nextLine().trim()); int[] hostNeeds new int[subnetCount]; for (int i 0; i subnetCount; i) { // 每个数字表示对应子网至少需要容纳的主机数量。 hostNeeds[i] scanner.nextInt(); } System.out.print(String.join(,, solve(cidr, subnetCount, hostNeeds))); } }Gopackage main import ( bufio fmt os strconv strings ) func ipToNum(ip string) (uint64, bool) { parts : strings.Split(ip, .) if len(parts) ! 4 { return 0, false } // IPv4 可以看成 4 个 8 位数字拼在一起。 // 转成 32 位整数后网络地址对齐、子网块大小和起点递增都可以直接算。 var value uint64 for _, part : range parts { segment, err : strconv.Atoi(part) if err ! nil || segment 0 || segment 255 { // IPv4 每段必须是 0 到 255 的数字非法段直接让整个 CIDR 无效。 return 0, false } // 折算成 32 位整数后网络对齐和子网起点递增都能用整数完成。 value value*256 uint64(segment) } return value, true } func numToIP(value uint64) string { // 子网起点在程序里是整数输出给题目时要拆回点分十进制地址。 // 每一段只取 8 位对应 IPv4 的一个 0~255 字段。 return fmt.Sprintf( %d.%d.%d.%d, (value24)255, (value16)255, (value8)255, value255, ) } func requiredHostBits(hosts int) int { bits : 0 // bits 是子网内用于主机编号的位数共能组合出 2^bits 个地址。 // 全 0 的网络地址和全 1 的广播地址不能分配所以普通主机容量要减 2。 capacity : (1 bits) - 2 for capacity hosts { // 每个子网要扣除网络地址和广播地址所以可用容量按 2^bits - 2 计算。 bits capacity (1 bits) - 2 } return bits } func parseCIDR(cidr string) (uint64, int, bool) { slash : strings.Index(cidr, /) if slash 0 { return 0, 0, false } mask, err : strconv.Atoi(cidr[slash1:]) // CIDR 的 /24 表示前 24 位是固定网络号剩余 8 位用于网内地址。 if err ! nil || mask 0 || mask 30 { // 原始 /31 和 /32 没有普通可分配主机地址本题规则下直接判无效。 return 0, 0, false } base, ok : ipToNum(cidr[:slash]) if !ok { return 0, 0, false } hostBits : 32 - mask // networkMask 的网络位全为 1、主机位全为 0按位与会把 base 的主机位清空。 // 清空后仍等于 base才说明输入 IP 正好是网段起点。 networkMask : uint64(0xffffffff) ^ ((uint64(1) hostBits) - 1) if basenetworkMask ! base { // CIDR 的 IP 部分必须正好是网络地址否则后续子网划分整体偏移。 return 0, 0, false } return base, mask, true } func main() { in : bufio.NewReader(os.Stdin) var cidr string var subnetCount int fmt.Fscan(in, cidr, subnetCount) needs : make([]int, subnetCount) maxNeed : 0 for i : 0; i subnetCount; i { fmt.Fscan(in, needs[i]) if needs[i] maxNeed { maxNeed needs[i] } } base, originalMask, ok : parseCIDR(cidr) if !ok { return } // 等长子网的意思是每个子网大小相同所以容量要按照最大主机需求统一决定。 // 这样小需求子网会有余量大需求子网也不会放不下。 subnetHostBits : requiredHostBits(maxNeed) // 子网掩码等于 32 减主机位数主机位越多单个子网容量越大。 subnetMask : 32 - subnetHostBits if subnetMask originalMask { // 等长子网如果比原始网段还大就无法在给定网段内分配。 return } // 新掩码每比原掩码多 1 位原网段就能多切一倍子网。 available : uint64(1) (subnetMask - originalMask) if available uint64(subnetCount) { // 原始网段能切出的等长子网数量不足按题意输出空字符串。 return } subnetSize : uint64(1) subnetHostBits answer : make([]string, 0, subnetCount) for i : 0; i subnetCount; i { // 第 i 个子网起点按统一块大小递增最后再转回点分十进制 CIDR。 start : base uint64(i)*subnetSize answer append(answer, numToIP(start)/strconv.Itoa(subnetMask)) } fmt.Print(strings.Join(answer, ,)) }C#include ctype.h #include stdio.h #include stdlib.h #include string.h int parse_ip_address(const char *text, unsigned long long *value) { const char *cursor text; unsigned long long result 0; // IPv4 由 4 个点分十进制字段组成这里逐段校验格式和值域。 // 同时把 a.b.c.d 折算成一个 32 位整数方便后面用掩码判断网络地址是否对齐。 for (int part_index 0; part_index 4; part_index) { if (!isdigit((unsigned char)*cursor)) { return 0; } int part 0; while (isdigit((unsigned char)*cursor)) { part part * 10 (*cursor - 0); if (part 255) { // IPv4 每段超过 255 就不是合法地址不能继续做掩码和子网计算。 return 0; } cursor; } result result * 256 part; if (part_index 3) { if (*cursor ! .) { return 0; } cursor; } else if (*cursor ! \0) { return 0; } } *value result; return 1; } int parse_positive_int(const char *text, int *value) { if (*text \0) { return 0; } int result 0; for (int i 0; text[i] ! \0; i) { if (!isdigit((unsigned char)text[i])) { return 0; } result result * 10 (text[i] - 0); } *value result; return 1; } int required_host_bits(int host_count) { int host_bits 0; // host_bits 是子网中用于主机编号的位数共有 2^host_bits 种地址组合。 // 全 0 是网络地址、全 1 是广播地址不能分配给主机所以可用数要减 2。 while (((1LL host_bits) - 2) host_count) { host_bits; } return host_bits; } void print_ip_address(unsigned long long value) { // 内部用整数计算子网起点输出时必须拆回普通读者熟悉的 a.b.c.d 格式。 // 每个右移结果都只保留 8 位因为 IPv4 的每段地址范围正好是 0 到 255。 printf( %llu.%llu.%llu.%llu, (value 24) 255, (value 16) 255, (value 8) 255, value 255 ); } int parse_cidr(char cidr[], unsigned long long *base, int *mask) { char *slash strchr(cidr, /); if (slash NULL) { return 0; } *slash \0; if (!parse_positive_int(slash 1, mask)) { return 0; } // CIDR 的 /24 表示前 24 位是固定网络号剩余 8 位属于网内地址。 if (*mask 0 || *mask 30) { // 原始网段至少要能容纳普通主机地址/31 和 /32 在本题分配规则下无效。 return 0; } if (!parse_ip_address(cidr, base)) { return 0; } int host_bits 32 - *mask; // network_mask 的网络位全为 1、主机位全为 0按位与会清空 base 的主机位。 // 清空后仍等于 base才能证明输入 IP 正好是网段起点。 unsigned long long network_mask 0xffffffffULL ^ ((1ULL host_bits) - 1); if ((*base network_mask) ! *base) { // CIDR 的 IP 部分必须是网络地址如果不是对齐起点后续子网起点都会错。 return 0; } return 1; } int main(void) { char cidr[128]; int subnet_count 0; int needs[10000]; if (scanf(%127s, cidr) ! 1) { return 0; } if (scanf(%d, subnet_count) ! 1) { return 0; } for (int i 0; i subnet_count; i) { scanf(%d, needs[i]); } unsigned long long base 0; int original_mask 0; if (!parse_cidr(cidr, base, original_mask)) { return 0; } // 等长划分意味着每个子网容量都一样所以统一容量必须能容纳最大的主机需求。 // max_need 用来决定子网主机位数不能按平均需求或第一个需求来算。 int max_need 0; for (int i 0; i subnet_count; i) { if (needs[i] max_need) { max_need needs[i]; } } int subnet_host_bits required_host_bits(max_need); // 子网掩码等于 32 减主机位数主机位越多单个等长子网越大。 int subnet_mask 32 - subnet_host_bits; if (subnet_mask original_mask) { // 单个等长子网如果比原网段还大就不可能在原网段内完成分配。 return 0; } // 新掩码每比原掩码多 1 位就多切一倍子网所以数量是 2 的差值次方。 unsigned long long available 1ULL (subnet_mask - original_mask); if (available (unsigned long long)subnet_count) { // 原网段切出的等长子网数量不足时题目要求不给出任何分配结果。 return 0; } unsigned long long subnet_size 1ULL subnet_host_bits; for (int i 0; i subnet_count; i) { if (i 0) { printf(,); } // 子网按起始地址递增输出第 i 个起点是 base 加 i 个统一块大小。 print_ip_address(base (unsigned long long)i * subnet_size); printf(/%d, subnet_mask); } return 0; }【华为od机试真题PythonJSJavaGo合集】【超值优惠】Py/JS/Java/Go合集【华为od机试真题Python】Python真题题库【华为od机试真题JavaScript】JavaScript真题题库【华为od机试真题JavaGo】JavaGo真题题库【华为od机试真题C】C真题题库【华为od机试真题C语言】C语言真题题库【华为od面试手撕代码题库】面试手撕代码题库【华为od机试面试交流群】【文章底部有二维码链接可扫码加交流群】华为OD机试:二本院校有机会吗? 有机会,但不大,大神除外!机考分数越高越好,所以需要提前刷题。机考通过后,如果没有收到面试邀请,也不要着急,非目标院校面试邀请发的时间比较晚。非目标院校今年有点难,机试至少要考到350分,所以需要疯狂刷题,华为OD机考是有题库的,最好在考前完所有题库题目。华为OD机试:跨专业可以参加华为OD可以,但是如果你的本科院校比较差,上岸概率不大。华为OD机试:华为OD简历被锁定机试通过,性格测试也通过,但是没人联系面试,发现简历被锁定。此时需要主动去联系HR。让他帮助你查询原因。
返回列表