任务 · 字符串 困难 JavaScript ·
Brace expansion
Expand braces the way a shell does and return all the resulting strings in order. s has lowercase letters, "{", "}" and ",".
- Braces are matched like brackets, left to right: each "}" closes the nearest unclosed "{". A "}" with nothing to close and a "{" that is never closed are ordinary characters. - A matched pair with at least one comma directly inside it (not inside a nested pair) is a group: the commas split it into alternatives, each expanded on its own, and the group stands for all their results in order. "{a,b{c,d}}" gives "a", "bc", "bd". Alternatives can be empty: "x{,y}" gives "x", "xy". - A matched pair without such a comma is kept literally, braces included, though groups inside it still expand: "{a}" gives "{a}" and "{{a,b}}" gives "{a}", "{b}". - Everything else is literal, including commas outside groups. Pieces next to each other combine in every way, the left piece varying slowest: "{a,b}{c,d}" gives "ac", "ad", "bc", "bd". Duplicates are kept.
The result has at most 100,000 strings; s can be up to 100,000 characters long and nest up to 300 levels deep.
函数签名
/**
* @param {string} s
* @returns {string[]}
*/
function brace_expand(s)示例
brace_expand("a{b,c}d") // -> ["abd", "acd"]
brace_expand("{a,b}{c,d}") // -> ["ac", "ad", "bc", "bd"]
brace_expand("{a}") // -> ["{a}"]另有 16 个隐藏测试和 3 个限时海量数据测试;其输入数据不公开。 任务以英文提示词提供给模型。
第 1 名Google Gemini 3.8 Flash未解决 · 通过 21/22 个测试生成耗时 9.6 秒 · 执行耗时 743 毫秒 · $0.0053 ✓ brace_expand("a{b,c}d")预期 ["abd", "acd"] 21 毫秒 ✓ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"] <1 毫秒 ✓ brace_expand("{a}")预期 ["{a}"] 2 毫秒 ✓ <1 毫秒✓ 2 毫秒✓ 1 毫秒✓ 1 毫秒✓ 2 毫秒✓ 2 毫秒✓ 2 毫秒✓ 3 毫秒✓ <1 毫秒✓ <1 毫秒✓ <1 毫秒✓ 2 毫秒✓ <1 毫秒✓ <1 毫秒✓ 1 毫秒✓ 1 毫秒⏱ 超出时间限制⏱ 63 毫秒⏱ 335 毫秒代码
/** * @param {string} s * @returns {string[]} */ function brace_expand(s) { const n = s.length; // Step 1: Match braces // Braces are matched left to right: each '}' closes nearest unclosed '{'. // Unmatched braces are ordinary characters. const match = new Int32Array(n).fill(-1); const stack = []; for (let i = 0; i < n; i++) { if (s.charCodeAt(i) === 123) { // '{' stack.push(i); } else if (s.charCodeAt(i) === 125) { // '}' if (stack.length > 0) { const open = stack.pop(); match[open] = i; match[i] = open; } } } // Step 2: Determine for each matched '{' whether it is a valid group (has comma directly inside) const isGroup = new Uint8Array(n); for (let i = 0; i < n; i++) { if (s.charCodeAt(i) === 123 && match[i] !== -1) { const close = match[i]; let hasComma = false; let j = i + 1; while (j < close) { const c = s.charCodeAt(j); if (c === 44) { // ',' hasComma = true; break; } if (c === 123 && match[j] !== -1) { j = match[j] + 1; } else { j++; } } if (hasComma) { isGroup[i] = 1; } } } // Parse [start, end) into an AST or expand directly // Note: result has at most 100,000 strings. // Recursion depth up to 300 levels deep. function expand(start, end) { // Collect sequence of parts const parts = []; let i = start; let literalBuf = ''; while (i < end) { const c = s.charCodeAt(i); if (c === 123 && match[i] !== -1 && match[i] < end) { const close = match[i]; if (isGroup[i]) { if (literalBuf.length > 0) { parts.push([literalBuf]); literalBuf = ''; } // Split by top-level commas inside [i + 1, close) const alternatives = []; let segStart = i + 1; let k = i + 1; while (k < close) { const kc = s.charCodeAt(k); if (kc === 44) { // ',' alternatives.push(expand(segStart, k)); segStart = k + 1; k++; } else if (kc === 123 && match[k] !== -1 && match[k] < close) { k = match[k] + 1; } else { k++; } } alternatives.push(expand(segStart, close)); // Flatten alternatives const groupRes = []; for (const alt of alternatives) { for (let a = 0; a < alt.length; a++) { groupRes.push(alt[a]); } } parts.push(groupRes); i = close + 1; } else { // Matched pair without top-level comma: kept literally, braces included, // though groups inside it still expand! // "{a}" -> literal '{', expand(a), literal '}' if (literalBuf.length > 0) { parts.push([literalBuf]); literalBuf = ''; } const inner = expand(i + 1, close); const preserved = new Array(inner.length); for (let idx = 0; idx < inner.length; idx++) { preserved[idx] = '{' + inner[idx] + '}'; } parts.push(preserved); i = close + 1; } } else { literalBuf += s[i]; i++; } } if (literalBuf.length > 0) { parts.push([literalBuf]); } if (parts.length === 0) { return ['']; } // Cartesian product of parts let current = parts[0]; for (let p = 1; p < parts.length; p++) { const nextPart = parts[p]; const nextLen = nextPart.length; const curLen = current.length; const combined = new Array(curLen * nextLen); let ptr = 0; for (let cIdx = 0; cIdx < curLen; cIdx++) { const prefix = current[cIdx]; for (let nIdx = 0; nIdx < nextLen; nIdx++) { combined[ptr++] = prefix + nextPart[nIdx]; } } current = combined; } return current; } return expand(0, n); }二次尝试
未解决 · 通过 21/22 个测试生成耗时 13 秒 · $0.0074模型可以看到失败的测试数量、包含预期值和返回值的失败示例,以及隐藏测试未通过的原因(不含输入数据)。此成绩不计入排名或评分。
✓ brace_expand("a{b,c}d")预期 ["abd", "acd"] 3 毫秒 ✓ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"] 2 毫秒 ✓ brace_expand("{a}")预期 ["{a}"] 1 毫秒 ✓ <1 毫秒✓ 1 毫秒✓ 3 毫秒✓ 2 毫秒✓ 2 毫秒✓ 2 毫秒✓ 2 毫秒✓ 1 毫秒✓ 1 毫秒✓ <1 毫秒✓ 2 毫秒✓ 2 毫秒✓ 1 毫秒✓ 2 毫秒✓ 1 毫秒✓ <1 毫秒⏱ 超出时间限制⏱ 43 毫秒⏱ 187 毫秒代码
/** * @param {string} s * @returns {string[]} */ function brace_expand(s) { const n = s.length; if (n === 0) return ['']; const match = new Int32Array(n).fill(-1); const stack = []; for (let i = 0; i < n; i++) { const code = s.charCodeAt(i); if (code === 123) { // '{' stack.push(i); } else if (code === 125) { // '}' if (stack.length > 0) { const open = stack.pop(); match[open] = i; match[i] = open; } } } // Check if each matched brace contains any unnested comma or groups inside // hasGroup[i] = whether anything expands inside (groups or nested groups) const isGroup = new Uint8Array(n); const hasExpansion = new Uint8Array(n); for (let i = n - 1; i >= 0; i--) { if (s.charCodeAt(i) === 123 && match[i] !== -1) { const close = match[i]; let hasComma = false; let anyExpand = false; let j = i + 1; while (j < close) { const c = s.charCodeAt(j); if (c === 44) { hasComma = true; j++; } else if (c === 123 && match[j] !== -1 && match[j] < close) { if (isGroup[j] || hasExpansion[j]) { anyExpand = true; } j = match[j] + 1; } else { j++; } } if (hasComma) { isGroup[i] = 1; hasExpansion[i] = 1; } else if (anyExpand) { hasExpansion[i] = 1; } } } // Quick check: does the whole string have any group expansion? let hasAnyGroup = false; for (let i = 0; i < n; i++) { if (isGroup[i]) { hasAnyGroup = true; break; } } if (!hasAnyGroup) { return [s]; } function expand(start, end) { const parts = []; let i = start; let litStart = start; while (i < end) { const c = s.charCodeAt(i); if (c === 123 && match[i] !== -1 && match[i] < end) { const close = match[i]; if (isGroup[i]) { if (i > litStart) { parts.push([s.slice(litStart, i)]); } const groupRes = []; let segStart = i + 1; let k = i + 1; while (k < close) { const kc = s.charCodeAt(k); if (kc === 44) { const alt = expand(segStart, k); for (let a = 0; a < alt.length; a++) groupRes.push(alt[a]); segStart = k + 1; k++; } else if (kc === 123 && match[k] !== -1 && match[k] < close) { k = match[k] + 1; } else { k++; } } const lastAlt = expand(segStart, close); for (let a = 0; a < lastAlt.length; a++) groupRes.push(lastAlt[a]); parts.push(groupRes); i = close + 1; litStart = i; } else if (hasExpansion[i]) { if (i > litStart) { parts.push([s.slice(litStart, i)]); } const inner = expand(i + 1, close); const preserved = new Array(inner.length); for (let idx = 0; idx < inner.length; idx++) { preserved[idx] = '{' + inner[idx] + '}'; } parts.push(preserved); i = close + 1; litStart = i; } else { // No expansion inside this brace pair, treat entire { ... } as literal i = close + 1; } } else { i++; } } if (i > litStart) { parts.push([s.slice(litStart, i)]); } if (parts.length === 0) { return ['']; } let current = parts[0]; for (let p = 1; p < parts.length; p++) { const nextPart = parts[p]; const nextLen = nextPart.length; const curLen = current.length; if (curLen === 1 && current[0] === '') { current = nextPart; continue; } if (nextLen === 1 && nextPart[0] === '') { continue; } if (nextLen === 1) { const suffix = nextPart[0]; const combined = new Array(curLen); for (let cIdx = 0; cIdx < curLen; cIdx++) { combined[cIdx] = current[cIdx] + suffix; } current = combined; } else if (curLen === 1) { const prefix = current[0]; const combined = new Array(nextLen); for (let nIdx = 0; nIdx < nextLen; nIdx++) { combined[nIdx] = prefix + nextPart[nIdx]; } current = combined; } else { const combined = new Array(curLen * nextLen); let ptr = 0; for (let cIdx = 0; cIdx < curLen; cIdx++) { const prefix = current[cIdx]; for (let nIdx = 0; nIdx < nextLen; nIdx++) { combined[ptr++] = prefix + nextPart[nIdx]; } } current = combined; } } return current; } return expand(0, n); }第 2 名OpenAI GPT-6.1 Terra未解决 · 通过 20/22 个测试生成耗时 10 秒 · 执行耗时 781 毫秒 · $0.0046 ✓ brace_expand("a{b,c}d")预期 ["abd", "acd"] 3 毫秒 ✓ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"] 1 毫秒 ✓ brace_expand("{a}")预期 ["{a}"] 2 毫秒 ✓ <1 毫秒✓ 1 毫秒✓ 1 毫秒✓ 1 毫秒✓ 6 毫秒✓ 2 毫秒✓ 2 毫秒✓ 28 毫秒✓ <1 毫秒✓ 2 毫秒✓ <1 毫秒✓ <1 毫秒✓ 3 毫秒✓ 2 毫秒✓ 1 毫秒✓ 1 毫秒⏱ 超出时间限制⏱ 53 毫秒⏱ 超出时间限制代码
function brace_expand(s) { const n = s.length; const match = new Int32Array(n); match.fill(-1); const stack = []; for (let i = 0; i < n; i++) { const c = s.charCodeAt(i); if (c === 123) { stack.push(i); } else if (c === 125 && stack.length) { const open = stack.pop(); match[open] = i; } } // Parse matched pairs into concatenation and alternative nodes. // Unmatched braces are included in literal substrings. const root = { parts: [], start: 0, open: -1, alternatives: null }; const frames = [root]; for (let i = 0; i < n; i++) { const frame = frames[frames.length - 1]; const c = s.charCodeAt(i); if (c === 123 && match[i] !== -1) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); frames.push({ parts: [], start: i + 1, open: i, alternatives: null }); } else if (c === 44 && frame.open !== -1) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); if (frame.alternatives === null) frame.alternatives = []; frame.alternatives.push(frame.parts); frame.parts = []; frame.start = i + 1; } else if (c === 125 && frame.open !== -1 && match[frame.open] === i) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); frames.pop(); let node; if (frame.alternatives !== null) { frame.alternatives.push(frame.parts); node = { alternatives: frame.alternatives }; } else { node = { literalBraces: true, parts: frame.parts }; } const parent = frames[frames.length - 1]; parent.parts.push(node); parent.start = i + 1; } } if (root.start < n) root.parts.push(s.slice(root.start)); function combine(left, right) { if (right.length === 1 && right[0] === "") return left; if (left.length === 1 && left[0] === "") return right; const result = new Array(left.length * right.length); let k = 0; for (let i = 0; i < left.length; i++) { for (let j = 0; j < right.length; j++) { result[k++] = left[i] + right[j]; } } return result; } function expandParts(parts) { let result = [""]; for (let i = 0; i < parts.length; i++) { const part = parts[i]; let values; if (typeof part === "string") { values = [part]; } else if (part.literalBraces) { values = expandParts(part.parts); for (let j = 0; j < values.length; j++) { values[j] = "{" + values[j] + "}"; } } else { values = []; for (let j = 0; j < part.alternatives.length; j++) { const expanded = expandParts(part.alternatives[j]); for (let k = 0; k < expanded.length; k++) values.push(expanded[k]); } } result = combine(result, values); } return result; } return expandParts(root.parts); }二次尝试
未解决 · 通过 20/22 个测试生成耗时 11 秒 · $0.0064模型可以看到失败的测试数量、包含预期值和返回值的失败示例,以及隐藏测试未通过的原因(不含输入数据)。此成绩不计入排名或评分。
✓ brace_expand("a{b,c}d")预期 ["abd", "acd"] 4 毫秒 ✓ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"] 3 毫秒 ✓ brace_expand("{a}")预期 ["{a}"] 2 毫秒 ✓ 4 毫秒✓ 2 毫秒✗ 答案错误✓ 2 毫秒✓ 3 毫秒✓ 1 毫秒✓ 2 毫秒✓ 2 毫秒✓ 1 毫秒✓ <1 毫秒✓ 1 毫秒✓ 1 毫秒✓ 2 毫秒✓ 1 毫秒✓ 1 毫秒✓ 1 毫秒⏱ 超出时间限制⏱ 68 毫秒⏱ 208 毫秒代码
function brace_expand(s) { const n = s.length; const match = new Int32Array(n); match.fill(-1); const stack = []; for (let i = 0; i < n; i++) { const c = s.charCodeAt(i); if (c === 123) { stack.push(i); } else if (c === 125 && stack.length) { match[stack.pop()] = i; } } const root = { parts: [], start: 0, open: -1, alternatives: null }; const frames = [root]; for (let i = 0; i < n; i++) { const frame = frames[frames.length - 1]; const c = s.charCodeAt(i); if (c === 123 && match[i] !== -1) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); frames.push({ parts: [], start: i + 1, open: i, alternatives: null }); } else if (c === 44 && frame.open !== -1) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); if (frame.alternatives === null) frame.alternatives = []; frame.alternatives.push(frame.parts); frame.parts = []; frame.start = i + 1; } else if (c === 125 && frame.open !== -1 && match[frame.open] === i) { if (frame.start < i) frame.parts.push(s.slice(frame.start, i)); frames.pop(); const parent = frames[frames.length - 1]; if (frame.alternatives === null) { parent.parts.push("{"); for (let j = 0; j < frame.parts.length; j++) { parent.parts.push(frame.parts[j]); } parent.parts.push("}"); } else { frame.alternatives.push(frame.parts); parent.parts.push(frame.alternatives); } parent.start = i + 1; } } if (root.start < n) root.parts.push(s.slice(root.start)); // Compile the expression into a sequence of literals and choice points. // Each alternative ends with a jump to the continuation. const code = []; function compile(parts) { let pending = ""; function flush() { if (pending) { code.push(pending); pending = ""; } } for (let i = 0; i < parts.length; i++) { const part = parts[i]; if (typeof part === "string") { pending += part; } else { flush(); const choice = { branches: [] }; code.push(choice); const jumps = []; for (let j = 0; j < part.length; j++) { choice.branches.push(code.length); compile(part[j]); if (j + 1 < part.length) { const jump = { target: 0 }; jumps.push(jump); code.push(jump); } } const end = code.length; for (let j = 0; j < jumps.length; j++) jumps[j].target = end; } } flush(); } compile(root.parts); const results = []; const pieces = []; const choices = []; let pc = 0; while (true) { while (pc < code.length) { const instruction = code[pc]; if (typeof instruction === "string") { pieces.push(instruction); pc++; } else if (instruction.branches) { const branches = instruction.branches; if (branches.length > 1) { choices.push({ branches, next: 1, length: pieces.length }); } pc = branches[0]; } else { pc = instruction.target; } } results.push(pieces.join("")); while (choices.length) { const choice = choices[choices.length - 1]; pieces.length = choice.length; pc = choice.branches[choice.next++]; if (choice.next === choice.branches.length) choices.pop(); break; } if (!choices.length && pc >= code.length) break; } return results; }第 3 名MoonshotAI Kimi K2.7 Code未解决 · 通过 0/22 个测试生成耗时 27 秒 · $0.02 回复被截断,代码不完整
✗ brace_expand("a{b,c}d")预期 ["abd", "acd"]回复中无代码 — ✗ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"]回复中无代码 — ✗ brace_expand("{a}")预期 ["{a}"]回复中无代码 — ✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码⏱ 回复中无代码⏱ 回复中无代码⏱ 回复中无代码第 3 名SpaceXAI Grok 4.7未解决 · 通过 0/22 个测试生成耗时 120 秒 回复中无代码
✗ brace_expand("a{b,c}d")预期 ["abd", "acd"]回复中无代码 — ✗ brace_expand("{a,b}{c,d}")预期 ["ac", "ad", "bc", "bd"]回复中无代码 — ✗ brace_expand("{a}")预期 ["{a}"]回复中无代码 — ✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码✗ 回复中无代码⏱ 回复中无代码⏱ 回复中无代码⏱ 回复中无代码
Token 成本: $0.04 · 轮次运行与评分规则 →