
目录题目思路Code题目题目内容当前有一组版本号列表单个版本号的格式为 Major.Minor.Patch-可选先行版本可选构建信息各字段含义如下。Major、Minor、Patch 为三个非负整数之间用点号分隔且禁止前导零。先行版本信息与构建信息都是可选项由字母、数字以及符号点号和短横线组成。先行版本信息以第一个短横线为分隔符构建信息以第一个加号为分隔符。请求返回列表中最大的版本号。若列表中存在不满足规则的版本号返回空字符串。优先比较规则如下。从左至右比较 Major、Minor、Patch 的数字大小大的优先。若三个数字都相同则继续对比先行版本信息有信息的大于无信息的。若先行版本信息也相同则对比构建信息有信息的大于无信息的。先行版本和构建信息若包含点号则先按点号切分成若干元素比较前一个元素相同时再比较下一个元素依次类推。单个元素的比较规则如下。两个元素都为纯数字时按数值大小比较大的优先。其他情况按 ASCII 字典序比较大的优先即 1 小于 A 小于 a。前缀相同时内容多的优先例如 a-b 小于 a-b-c。输入描述本题为核心代码模式需要实现函数 maxVersion(versions)。参数 versions 为版本号字符串列表长度 n 满足 1 n 100。单个版本号字符串长度满足 0 len 1024。其中构成字符串的每项值范围为 0 x 2^31非纯数字字段长度不超过 1024。合法先行版本信息和构建信息要求任意分隔符之间的内容不为空只能出现字母、数字、短横线和点号不出现下划线和波浪线不以符号开头或结尾纯数字串不允许有前导零分隔符最多出现一次。本地命令行版本支持输入形如 versions [0.0.1,0.1.1,1.0.0] 的一行文本也支持直接输入 JSON 风格字符串数组。输出描述返回列表中最大的版本号字符串。若列表中存在不合规格式的版本号返回空字符串。样例 1输入versions [0.0.1,0.1.1,1.0.0]输出1.0.0说明三个版本号按 Major、Minor、Patch 比较1.0.0 最大。思路整体思路先把每个版本号解析成主版本、次版本、修订号、先行版本信息和构建信息五部分任何一个版本号不合法时直接返回空字符串。第一步按加号和短横线拆出构建信息与先行版本信息再检查主体部分是否恰好包含三个非负整数字段。这样可以先把格式合法性和比较逻辑分离避免比较时还要处理异常字符串。第二步Major、Minor、Patch 按整数从左到右比较因为这三项是版本优先级最高的确定字段。第三步当三个数字都相等时分别比较先行版本和构建信息。第四步先行版本和构建信息内部按点号拆分元素。两个纯数字元素按数值比较否则按 ASCII 字典序比较若前缀完全相同元素更多的一方更大。边界处理只要出现前导零、空字段、非法字符、符号开头或结尾、重复分隔符等格式问题就返回空字符串。复杂度分析设版本数量为 n单个版本号最大长度为 L。解析和比较都只线性扫描字符串时间复杂度 O(nL)空间复杂度 O(nL)。Codeimport re import sys MAX_VALUE 2 ** 31 # 本地输入兼容 versions [...]先提取双引号里的版本号字符串。 def split_versions(text): quoted re.findall(r([^]*), text) # 主体版本必须恰好是 Major、Minor、Patch 三个数字字段。 if quoted: return quoted # 数字字段禁止前导零避免 01 和 1 在格式上产生歧义。 return [part for part in re.split(r[\s,], text.strip()) if part] def valid_number(token): # 先拆构建信息再拆先行版本信息保证分隔符作用范围正确。 if not token.isdigit(): return False # 先行版本和构建信息内部按点号拆成多个比较元素。 if len(token) 1 and token[0] 0: return False # 元素为空、字符非法或纯数字前导零时整个版本列表返回空字符串。 return int(token) MAX_VALUE def parse_identifier(text): # Major、Minor、Patch 优先级最高按整数从左到右比较。 if text is None: return [] # 题目规则规定有先行或构建信息的大于没有信息的版本。 if not text or text[0] in .- or text[-1] in .-: return None # 版本完全相等时不更新 best保留列表中最早出现的版本。 if not re.fullmatch(r[A-Za-z0-9.-], text): return None parts text.split(.) for part in parts: if part : return None if part.isdigit() and not valid_number(part): return None return parts def parse_version(version): if version.count() 1: return None main_and_pre, build (version.split(, 1) [None])[:2] if in version else (version, None) if main_and_pre.count(-) 1: return None core, pre (main_and_pre.split(-, 1) [None])[:2] if - in main_and_pre else (main_and_pre, None) nums core.split(.) if len(nums) ! 3 or any(not valid_number(x) for x in nums): return None pre_parts parse_identifier(pre) build_parts parse_identifier(build) if pre_parts is None or build_parts is None: return None return (list(map(int, nums)), pre_parts, build_parts, version) def compare_parts(a, b): if not a and not b: return 0 if a and not b: return 1 if b and not a: return -1 for x, y in zip(a, b): if x y: continue if x.isdigit() and y.isdigit(): return 1 if int(x) int(y) else -1 return 1 if x y else -1 if len(a) len(b): return 0 # 前面字段都相同的时候字段更多的一方优先级更高。 return 1 if len(a) len(b) else -1 def compare(a, b): for x, y in zip(a[0], b[0]): if x ! y: return 1 if x y else -1 pre_cmp compare_parts(a[1], b[1]) if pre_cmp: return pre_cmp return compare_parts(a[2], b[2]) def solve(versions): parsed [] for version in versions: item parse_version(version) if item is None: return parsed.append(item) best parsed[0] for item in parsed[1:]: # 只在遇到严格更大的版本时替换完全相等时保留原列表中更早出现的版本。 if compare(item, best) 0: best item return best[3] print(solve(split_versions(sys.stdin.read())))JSconst fs require(fs); // 本地输入兼容 versions [...]先提取双引号里的版本号字符串。 const text fs.readFileSync(0, utf8); const MAX_VALUE 2 ** 31; // 主体版本必须恰好是 Major、Minor、Patch 三个数字字段。 function splitVersions(text) { const matches [...text.matchAll(/([^]*)/g)].map((m) m[1]); // 数字字段禁止前导零避免 01 和 1 在格式上产生歧义。 if (matches.length 0) return matches; return text.trim().split(/[\s,]/).filter(Boolean); } function validNumber(token) { // 先拆构建信息再拆先行版本信息保证分隔符作用范围正确。 if (!/^\d$/.test(token)) return false; if (token.length 1 token[0] 0) return false; // 先行版本和构建信息内部按点号拆成多个比较元素。 return Number(token) MAX_VALUE; } function parseIdentifier(text) { // 元素为空、字符非法或纯数字前导零时整个版本列表返回空字符串。 if (text null) return []; if (text || /^[.-]/.test(text) || /[.-]$/.test(text)) return null; // Major、Minor、Patch 优先级最高按整数从左到右比较。 if (!/^[A-Za-z0-9.-]$/.test(text)) return null; const parts text.split(.); // 题目规则规定有先行或构建信息的大于没有信息的版本。 for (const part of parts) { if (part ) return null; // 版本完全相等时不更新 best保留列表中最早出现的版本。 if (/^\d$/.test(part) !validNumber(part)) return null; } return parts; } function parseVersion(raw) { if ((raw.match(/\/g) || []).length 1) return null; let mainAndPre raw; let build null; if (raw.includes()) [mainAndPre, build] raw.split(); if ((mainAndPre.match(/-/g) || []).length 1) return null; let core mainAndPre; let pre null; if (mainAndPre.includes(-)) [core, pre] mainAndPre.split(-); const numsText core.split(.); if (numsText.length ! 3 || numsText.some((x) !validNumber(x))) return null; const preParts parseIdentifier(pre); const buildParts parseIdentifier(build); if (preParts null || buildParts null) return null; return { nums: numsText.map(Number), pre: preParts, build: buildParts, raw }; } function compareParts(a, b) { if (a.length 0 b.length 0) return 0; if (a.length 0 b.length 0) return 1; if (a.length 0) return -1; const m Math.min(a.length, b.length); for (let i 0; i m; i) { if (a[i] b[i]) continue; // 两边都是数字字段时按数值比较避免字典序把 10 排在 2 前面。 if (/^\d$/.test(a[i]) /^\d$/.test(b[i])) return Number(a[i]) Number(b[i]) ? 1 : -1; return a[i] b[i] ? 1 : -1; } return Math.sign(a.length - b.length); } function compareVersion(a, b) { for (let i 0; i 3; i) { if (a.nums[i] ! b.nums[i]) return a.nums[i] b.nums[i] ? 1 : -1; } const preCmp compareParts(a.pre, b.pre); return preCmp ! 0 ? preCmp : compareParts(a.build, b.build); } const parsed []; for (const raw of splitVersions(text)) { const item parseVersion(raw); if (item null) { process.exit(0); } parsed.push(item); } let best 0; for (let i 1; i parsed.length; i) { // 只在当前版本严格更大时替换 best相等时保留更早出现的版本。 if (compareVersion(parsed[i], parsed[best]) 0) best i; } process.stdout.write(parsed.length ? parsed[best].raw : );【华为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。让他帮助你查询原因。