题目重点:将不同时选择首尾转换为两条线性DP,处理单元素与常数辅助空间。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 非负整数值,环中相邻房子不能同时选,可不选;首尾相邻。
- 训练空数组0、单房可选、两房最多一房;这些边界是标准训练合同。
解题路线
- n≥2时合法解不能同时选0和n-1,因此至少排除一端。分别算[0,n-2]与[1,n-1]线性最大非相邻和,取max。
- 线性递推D[i]=max(D[i-1],D[i-2]+value[i]),两项对应不选与选当前;保留两个旧状态即可,不需要全DP数组。
- 两子问题可能重叠同一解,但只取最大不计数量,所以重复不影响正确性。每个合法环形解至少在一子问题,每个子问题解又是合法环形解。
- 单元素不能按排除端点两段都会空处理,独立返回本值;示例用索引范围不切片,才是真正O(1)辅助空间。
手动走一遍
训练[2,3,2]最大3不能选首尾2+2;[1,2,3,1]最大4;[5]返回5。
Python 参考实现
下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。
代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。
def maximum_nonadjacent_ring(values):
"""Nonnegative house values, first/last adjacent; single house may be chosen."""
if any(v<0 for v in values):raise ValueError("nonnegative values required")
if not values:return 0
if len(values)==1:return values[0]
def line(start,end):
before2=before1=0
for i in range(start,end):
before2,before1=before1,max(before1,before2+values[i])
return before1
return max(line(0,len(values)-1),line(1,len(values)))
复杂度
O(n)时间、O(1)辅助状态,输出仅金额;重建所选下标需要保存决策或再遍历。
易错点与追问
容易失分的边界
- 套线性DP选首尾。
- 单房排除后返回0。
- 用数组切片却声称无额外内存。
继续深挖
- 要返回最优集合怎么重建?
- 统计最优解数量怎样防两段重复?
- 环上距离2内不能同选怎样分情况?
