题目重点:同余类互不干扰,落点金币计一次,跳过的金币不计。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 字符T为初始棋子、C为金币、.为空;可任选棋子重复右移恰3格,落点不得有棋子,不能越界。
- 求任意合法调度的最大收集数;不固定棋子移动先后、回合数或代价。
解题路线
- 每次+3保持下标mod3。因此分成三个独立线性轨道,每轨仅能向右移动一格。没有初始棋子左侧金币永不可达,这是上界。
- 每段两个相邻初始棋子之间的金币,可由其左侧棋子依次收集;先调度较右棋子向右扫,再处理左棋子,已扫轨道上后续阻塞不会妨碍剩余金币。最后一个棋子右侧也能扫完。
- 所以每轨最左初始T之后所有C都可达,即达到上界。扫描并在每个同余轨道记录是否遇到T。不能把初始T当永久障碍,也不能只扫描相邻物理格。
手动走一遍
TC.C...:位置0的T只能到3、6,收集3的C,位置1的C无法到达,答案1。同一轨道的抽象串T C T C,右棋子先收右C,左棋子再收中间C,答案2。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def max_coins(board):
if any(c not in 'TC.' for c in board):
raise ValueError("expected T, C or dot")
# In each residue class, move the rightmost token first, then the next.
total = 0
for residue in range(3):
found = False
for i in range(residue, len(board), 3):
if board[i] == 'T':
found = True
elif board[i] == 'C' and found:
total += 1
return total
复杂度
O(n)时间、O(1)空间;三个轨道总计读取每格一次。
易错点与追问
容易失分的边界
- 移动时只看落点,不能经过C也算收集。
- 若要求固定轮流调度或限制步数,全部可达上界未必能达到。
继续深挖
- 怎样输出实现上界的具体操作序列,最坏需要多少次移动?
- 允许步长2或3时同余分解为什么失效?
