技术岗位 · Coding

棋子每次右跳三格:最多能收集多少金币

同余类互不干扰,落点金币计一次,跳过的金币不计。

题目重点:同余类互不干扰,落点金币计一次,跳过的金币不计。

题意与假设

这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。

  • 字符T为初始棋子、C为金币、.为空;可任选棋子重复右移恰3格,落点不得有棋子,不能越界。
  • 求任意合法调度的最大收集数;不固定棋子移动先后、回合数或代价。

解题路线

  1. 每次+3保持下标mod3。因此分成三个独立线性轨道,每轨仅能向右移动一格。没有初始棋子左侧金币永不可达,这是上界。
  2. 每段两个相邻初始棋子之间的金币,可由其左侧棋子依次收集;先调度较右棋子向右扫,再处理左棋子,已扫轨道上后续阻塞不会妨碍剩余金币。最后一个棋子右侧也能扫完。
  3. 所以每轨最左初始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时同余分解为什么失效?
✓已复制微信号!