Ruby数组相似元素索引校验:A/B计数逻辑错误排查与修复
猜数字游戏中A/B计数错误(重复元素处理问题)
问题描述
这是我在StackOverFlow上的第一个问题!如果问题表述不清,请告知我。
当前代码:
code = ["4", "4", "1", "1"] guess = ["4", "4", "4", "1"] @A = 0 @B = 0 code.each_with_index do |item, index| if item == guess[index] @A += 1 elsif code.include?(guess[index]) @B += 1 end print "\nA:#{@A} B:#{@B}" end
需求:
- 数字在两个数组相同索引位置 → @A加1
- 数字存在于两个数组但索引不同 → @B加1
预期结果:A:3、B:0,实际得到A:3、B:1。code数组中没有第三个"4",所以@B不应加1。
疑问:是否是因为.include?无法正确处理数组中的重复元素?该如何修复?
问题原因
没错,问题就出在include?方法上——它只判断元素是否存在,完全不考虑数组中剩余可用的重复元素数量。
当遍历到guess的第三个元素"4"时,code里的两个"4"已经和guess的前两个"4"匹配成A了,没有多余的"4"可以用来计算B,但include?还是会返回true,导致错误地给B加1。
修复方案
方案一:统计元素频率(简洁高效)
通过统计两个数组中每个元素的出现次数,先计算总共有多少个元素是双方共有的,再减去已匹配位置的A数量,得到最终的B数量:
code = ["4", "4", "1", "1"] guess = ["4", "4", "4", "1"] # 计算A的数量:统计索引和元素都匹配的次数 a_count = code.each_with_index.count { |item, idx| item == guess[idx] } # 统计两个数组中每个元素的出现频率 code_freq = code.tally guess_freq = guess.tally # 计算所有元素的最小出现次数之和(总共有多少个元素是双方共有的) total_common = code_freq.keys.sum { |key| [code_freq[key], guess_freq[key] || 0].min } # B的数量 = 总共有元素 - 已匹配位置的A数量 b_count = total_common - a_count puts "A:#{a_count} B:#{b_count}" # 输出:A:3 B:0
方案二:标记并移除已匹配元素(直观易懂)
先标记出已经匹配成A的元素,再遍历剩余元素计算B,每匹配一个就移除对应元素避免重复计数:
code = ["4", "4", "1", "1"].dup # 复制数组,避免修改原数据 guess = ["4", "4", "4", "1"] a_count = 0 b_count = 0 # 第一步:统计A,同时标记已匹配的元素 guess.each_with_index do |g_item, idx| if g_item == code[idx] a_count += 1 code[idx] = nil # 标记为已匹配,后续不再参与B的计算 end end # 第二步:统计B,只处理未匹配A的元素,且匹配后移除对应元素 guess.each_with_index do |g_item, idx| # 跳过已经匹配A的元素 next if code[idx].nil? if code.include?(g_item) b_count += 1 code[code.index(g_item)] = nil # 移除已匹配的元素,防止重复计算 end end puts "A:#{a_count} B:#{b_count}" # 输出:A:3 B:0
内容的提问来源于stack exchange,提问作者hpm00
相关产品推荐
相关产品推荐

