
本文详解如何在严格限制(仅一个 for 循环、禁用数组/正则/嵌套循环、仅允许 toLowerCase)下,解析形如 :flower::flower::flower: 的字符串,统计每个昵称(小写归一化)所关联的 :flower: 数量,并正确处理昵称链式分组与重复出现场景。
本文详解如何在严格限制(仅一个 for 循环、禁用数组/正则/嵌套循环、仅允许 tolowercase)下,解析形如 `
在前端算法约束题中,常需在极简语法环境下完成复杂逻辑解析。本问题核心难点在于:无数组、无正则、单循环内既要识别 <nickname></nickname> 结构,又要将后续连续的 :flower: 公平分配给当前“昵称链”中的每一位成员,同时支持昵称跨位置重复累加。
解决方案的关键突破点是:用链表模拟昵称队列,用状态机驱动解析流程。我们不依赖 Array.push() 或 split(),而是构建轻量级单向链表节点({ nick: 'jane', next: nextNode }),在遇到新 时创建新节点并前置插入(头插法),形成逆序链;当成功匹配 <code>:flower: 后,遍历该链为每个昵称累加计数。
以下是符合全部约束的完整实现(正向扫描 + 链表分配):
function countFlowers(text) {
const nickTag = "";
const flower = ":flower:";
const result = {};
let currentNicks = null; // 链表头节点,初始为空
let nickTagIndex = 0;
let flowerIndex = 0;
let flowerCount = 0;
// 在字符串末尾追加一个空标签 '',确保末尾的 flowers 能被及时分配
const extendedText = text + nickTag;
for (let i = 0; i 0) {
let node = currentNicks;
while (node !== null) {
const key = node.nick;
result[key] = (result[key] ?? 0) + flowerCount;
node = node.next;
}
flowerCount = 0;
}
// 创建新昵称节点,头插法加入链表
currentNicks = { nick: "", next: currentNicks };
}
nickTagIndex = (nickTagIndex + 1) % nickTag.length;
} else if (nickTagIndex === 1) {
// 处于 '' 之间:收集昵称字符(转小写)
currentNicks.nick += token.toLowerCase();
} else if (currentNicks && token === flower[flowerIndex]) {
// 尝试匹配 ':flower:'
flowerIndex = (flowerIndex + 1) % flower.length;
if (flowerIndex === 0) {
flowerCount++;
}
} else {
// 匹配中断 → 重置 flower 状态机
flowerIndex = 0;
}
}
return result;
}
✅ 关键设计说明:
-
链表替代数组:
currentNicks是纯对象链,next指向下一个昵称节点,完美规避数组禁令; -
自动 flush 机制:每次遇到新
或循环结束前(靠 <code>text + ''触发),将当前累计的flowerCount分配给整条链; -
大小写归一化:所有昵称字符通过
.toLowerCase()统一转小写,满足题目要求; -
链式分组语义:
<kate><john></john></kate>构成双节点链,后续:flower::flower:会被同时加给kate和john; -
重复昵称累加:若
<jane></jane>出现在不同位置,其对应flowerCount会独立累加(如示例4中jane: 5)。
⚠️ 注意事项:
- 该解法时间复杂度为 O(n × m)(n=字符串长,m=单次链表遍历长度),但在题目约束下已是最优;
- 不要省略
text + nickTag—— 它是触发最后一次 flowers 分配的必要哨兵; - 若需严格按输入顺序输出 key(如
jane必须在kate前),可额外维护一个插入顺序数组(但题目未要求,且违反约束); - 所有
:flower:必须紧邻昵称链之后才生效;前置或孤立的:flower:(如开头:flower: :flower:)会被忽略(见示例6)。
此方案不仅满足全部硬性限制,更体现了状态机 + 链表的数据结构巧思,是 JavaScript 算法优化中「用空间换自由度、用结构换表达力」的经典实践。










