Advent of Code 2023 Day1 Part2代码求助:测试通过输入计算错误
Advent of Code 2023 Day1 Part2 问题排查
我正在做2023年的Advent of Code,卡在了Day1 Part2的问题上。题目要求提取字符串中的首尾数字(英文数字如one也视为有效数字),将首尾数字组合成两位数后求和。我的代码在给定的测试数据中能得到正确结果281,但用官方输入数据计算出的总和54489是错误的,恳请帮忙指出错误所在。
测试数据示例
const testString: string[] = [ "two1nine", "eightwothree", "abcone2threexyz", "xtwone3four", "4nineeightseven2", "zoneight234", "7pqrstsixteen", ];
我的代码
const partTwo = () => { const testString: string[] = [ "two1nine", "eightwothree", "abcone2threexyz", "xtwone3four", "4nineeightseven2", "zoneight234", "7pqrstsixteen", ]; const filePath = "data.txt"; const dataArray: string[] = fs .readFileSync(filePath) .toString() .split("\n") .map((str: string) => str.replace("\r", "")); const numberMapping: Map<string, number> = new Map([ ["one", 1], ["two", 2], ["three", 3], ["four", 4], ["five", 5], ["six", 6], ["seven", 7], ["eight", 8], ["nine", 9], ]); const convertToInteger = (str: string): number => { const regexPattern = Array.from(numberMapping.keys()).join("|") + "|\\d"; const regex = new RegExp(regexPattern, "g"); const foundWords = str.match(regex); if (!foundWords || foundWords.length === 0) return 0; console.log(foundWords); const first = isNaN(parseInt(foundWords[0])) ? numberMapping.get(foundWords[0]) : parseInt(foundWords[0]); const last = isNaN(parseInt(foundWords[foundWords.length - 1])) ? numberMapping.get(foundWords[foundWords.length - 1]) : parseInt(foundWords[foundWords.length - 1]); return (first ?? 0) * 10 + (last ?? 0); }; const getTotalSum = (arr: number[]) => { return arr.reduce((acc, curr) => acc + curr, 0); } const result = dataArray.map((str) => convertToInteger(str)); const resultNumber = getTotalSum(result); const resultMap: Record<string, number> = {}; dataArray.forEach((str) => { resultMap[str] = convertToInteger(str); }); result.forEach((str, i) => console.log(`${dataArray[i]} - ${str}`)); console.log(result); console.log(resultNumber); };
部分计算结果
2qlljdqcbeight - 28 eight47srvbfive - 85 slconeightfoureight557m38 - 18 xvqeightwosixnine61eightsn2tdczfhx - 82 msixonexch1twokjbdlhchqk1 - 61 112ninejlhhjmjzkzgdsix - 16 6six7jr - 67 878eightgvsqvzfthree - 83 2jxzhlkhdktxfjjleightdfpgfxjv - 28 mxbzgzg5three - 53 33fivehcxcxhsqhtwo - 32 bhfive4ths1811seven - 57 eightfxkpsqjlpjgjcp12twoxkhllqzq7 - 87 sixkvvhvgtcnjhjtmxnr7seven8 - 68 csdeightwobtsxflml4eightbxbzmvhq2four - 84 twoplpbhq3mkkhb2 - 22 1sevenrsgrl76rqtsqqzkncrgznine - 19 6twolnlq - 62 nine567 - 97 qjvhrrtdqgsp8pxrlslvtwothree9three3 - 83 ninekxpninedjx7phcncpzq - 97 onegmzclftbt8sixmkfnqpeight - 18 one53foureightzpvseven9 - 19 315foursixonefcvttgrknrgf1 - 31 and more...
错误原因分析
问题出在正则表达式的匹配逻辑上:当前使用的全局正则/one|two|...|nine|\d/g会从上次匹配结束的位置继续匹配,无法处理重叠的数字字符串。
比如字符串oneight,它同时包含one和eight,但正则会先匹配one,然后指针跳到one之后的位置(即i的位置),剩下的ight无法匹配到eight,导致最终取到的首尾数字都是one对应的1,得到错误的11,而正确结果应该是18。
类似的重叠场景还有twone(包含two和one)、threeight(包含three和eight)等,这些情况在官方输入中大概率存在,导致总和计算错误。
修正方案
使用**正向预查(lookahead)**实现重叠匹配,让正则可以在每个位置检查是否存在匹配的数字(无论是英文还是阿拉伯数字),而不会移动匹配指针。修改convertToInteger函数中的正则匹配逻辑:
const convertToInteger = (str: string): number => { const regex = new RegExp(`(?=(${Array.from(numberMapping.keys()).join("|")}|\\d))`, "g"); const foundWords: string[] = []; let match: RegExpExecArray | null; // 循环捕获所有匹配的数字(包括重叠的) while ((match = regex.exec(str)) !== null) { if (match[1]) { foundWords.push(match[1]); } } if (foundWords.length === 0) return 0; const first = isNaN(parseInt(foundWords[0])) ? numberMapping.get(foundWords[0]) : parseInt(foundWords[0]); const last = isNaN(parseInt(foundWords[foundWords.length - 1])) ? numberMapping.get(foundWords[foundWords.length - 1]) : parseInt(foundWords[foundWords.length - 1]); return (first ?? 0) * 10 + (last ?? 0); };
这个修改后的逻辑会遍历字符串的每个位置,通过正向预查捕获所有可能的数字(包括重叠的),确保不会漏掉任何应该被识别的首尾数字。
内容的提问来源于stack exchange,提问作者Sitthata
相关产品推荐
相关产品推荐

