卡牌取数最大化得分算法验证失败,请求错误排查
卡牌取数问题代码错误分析
问题回顾
桌上排列着一排卡牌,每张卡牌上写有一个自然数。每次操作可从这排卡牌的左端或右端取一张卡牌,总共可进行k次操作。最终得分等于所取卡牌上数字的总和,需确定游戏结束时能获得的最大得分。
你的代码:
def card_counter(arr, k): if len(arr) == k: return sum(arr) rang = len(arr) // 2 left = arr[:rang] right = list(reversed(arr[rang:])) c = 0 for _ in range(k): min_arr = left if sum(left) >= sum( right) and len(left) > 0 else right c += min_arr.pop(0) return c if __name__ == '__main__': assert card_counter([1, 2, 3, 4, 5], 5) == 15 assert card_counter([0, 0, 0], 1) == 0 assert card_counter([150], 1) == 150
错误原因分析
你的代码能通过自行设计的测试用例,但系统测试失败,核心问题出在策略逻辑完全错误,具体如下:
- 取数策略不符合最优要求:你把数组硬切成左右两半,每次选当前两半总和较大的区域取数,这种逻辑根本无法覆盖所有最优取数组合。比如测试用例
arr=[4,3,2,5], k=3,最优得分是取左2个+右1个(4+3+5=12),但你的代码会取左1个+右2个(4+5+2=11),得到错误结果。 - 数组分半逻辑无依据:用
len(arr)//2分割数组完全是主观臆断,和问题的最优解没有任何关联,直接限制了取数的选择范围,漏掉了很多左端+右端的组合可能。 - 循环取数逻辑僵化:你对右半区做了反转,每次取
pop(0),这种方式只能在固定半区里依次取数,无法灵活调整左端和右端的取数次数,自然得不到最优解。
正确思路与代码
正确的做法是枚举所有可能的取数组合:取i个左端元素,同时取k-i个右端元素(i的范围是0到k,且要保证取数不超过数组长度),计算每种组合的总和,最终取最大值。可以用前缀和来优化计算效率:
def card_counter(arr, k): n = len(arr) max_sum = 0 # 前缀和数组,prefix[i]表示前i个元素的累加和 prefix = [0] * (n + 1) for i in range(n): prefix[i+1] = prefix[i] + arr[i] # 枚举所有左端取i个、右端取k-i个的情况 for i in range(k + 1): right_count = k - i # 过滤掉超出数组长度的无效情况 if i > n or right_count < 0 or right_count > n: continue # 计算当前组合的总和:左端i个的和 + 右端right_count个的和 current_sum = prefix[i] + (prefix[n] - prefix[n - right_count]) if current_sum > max_sum: max_sum = current_sum return max_sum
这个代码可以正确处理所有场景,包括之前的反例:card_counter([4,3,2,5],3)会返回12,符合最优解。
内容的提问来源于stack exchange,提问作者Cooke09
相关产品推荐
相关产品推荐

