CodeWars练习:首非重复字符函数返回值不符合预期的问题
问题:无法返回第一个不重复字符的正确大小写
题目要求
编写函数接收字符串输入,返回第一个不重复的字符:
- 示例:输入
'stress'返回't',因为t仅出现一次且是第一个不重复字符 - 额外要求:大小写视为同一字符,但返回原字符的正确大小写,比如输入
'sTreSS'应返回'T' - 若所有字符重复,返回空字符串
""
我的代码
const firstNonRepeatingLetter = (string) => { const letters = {}; // 统计每个字母的出现次数(不区分大小写) string.split('') .forEach(letter => { letter = letter.toLowerCase(); if (letters[letter] !== undefined) letters[letter]++; if (letters[letter] === undefined) letters[letter] = 1; }); for (let key in letters) { let val = letters[key]; // 找到第一个出现次数为1的字母,判断原字符串中的大小写 if (val === 1) { string.split('') .forEach(letter => { // 第16行:如果字符串中的字母是对应key的大写形式,返回该字母 if (key.toUpperCase() === letter) return letter; }); // 否则返回key本身(小写) return key; }; }; return ''; };
遇到的问题
代码通过了大部分测试,但输入'sTreSS'时返回的是't'而不是预期的'T'。调试发现第16行的if条件触发时,局部返回值是'T',但forEach会继续执行,最终函数执行后续的return key语句返回了小写t。
问题原因分析
forEach的return无法终止外层函数:
forEach回调里的return只能结束当前这一次回调的执行,不能跳出外层的for...in循环或整个函数。所以当找到'T'时,回调里的return letter只是终止了当前回调,forEach会继续遍历剩下的字符,遍历完成后代码会执行后续的return key,返回小写的t。遍历顺序存在隐患:
for...in遍历对象属性的顺序不保证和原字符串中字符的出现顺序一致。你先统计所有字母的出现次数,再遍历对象找第一个次数为1的key,但这个key对应的字符在原字符串中不一定是第一个出现的不重复字符,可能导致返回错误结果。
修正方案
直接遍历原字符串,既保证顺序正确,又能直接返回原字符的大小写:
const firstNonRepeatingLetter = (string) => { const countMap = {}; // 先统计所有字符的出现次数(不区分大小写) string.split('').forEach(char => { const lowerChar = char.toLowerCase(); countMap[lowerChar] = (countMap[lowerChar] || 0) + 1; }); // 遍历原字符串,找到第一个出现次数为1的字符 for (const char of string) { if (countMap[char.toLowerCase()] === 1) { return char; } } return ''; };
方案说明
- 遍历原字符串保证了找到的是第一个出现的不重复字符,避免
for...in的顺序问题。 - 统计次数时用
(countMap[lowerChar] || 0) + 1简化代码,省去重复的undefined判断。 - 直接返回原字符串中的字符,自然保留了正确的大小写。
内容的提问来源于stack exchange,提问作者Neuroneer
相关产品推荐
相关产品推荐

