SWE · Coding

Meta 允许一次下降的最长连续片段:断点边界

寻找最长连续子数组,其中至多一对相邻元素发生下降,明确相等是否算break。

题目重点:寻找最长连续子数组,其中至多一对相邻元素发生下降,明确相等是否算break。

题意与假设

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

  • 训练以给定break定义next<previous为准,相等不算break,故其余部分非降序;若实际要求严格上升,则break判断改为next<=previous并重新测试。
  • 不能删除或修改元素,只允许片段内最多一个坏相邻关系。与“最多改变一个值使上升”是不同问题。

解题路线

  1. 记录最近下降边的右端previousDrop;遇新下降边时,窗口左端移到上一下降边的右端,从而排除旧坏边但保留新坏边。
  2. 每次处理right,窗口里至多一个下降,且left是能保证该性质的最早位置,故其长度是以right结束的最长合法长度。更新全局best。
  3. 不要把窗口移到新下降右端,那会同时丢掉允许保留的一次下降,退化为不允许break。空输入结果0。

手动走一遍

[1,4,2,3,1,5]:第二次下降在3→1,需把左端移到第一个下降的右端2所在位置,窗口[2,3,1,5]仍只含一次下降。最优长度4;[1,1,1]按本训练合同长度3。

Python 参考实现

下面的代码按上文假设实现,适合本地运行并追加自己的测试用例。

代码区可横向滚动;使用键盘时,先聚焦代码区再按方向键查看。

def longest_one_drop(values):
    """Longest nonempty contiguous window with <=1 edge where next < previous.

    Equal adjacent values do NOT count as a break under this declared contract.
    """
    left=0
    previous_drop=None
    best=0
    for right,value in enumerate(values):
        if right and value<values[right-1]:
            if previous_drop is not None:left=previous_drop
            previous_drop=right
        best=max(best,right-left+1)
    return best

复杂度

O(n)时间/O(1)辅助空间;所有状态仅left、最近断点与best。

易错点与追问

容易失分的边界

  • 文字“递增”与显式break<可能对等值有不同解释,必须先举[1,1]澄清。
  • 用修一个元素的解法会漏掉“保留下降但计次数”的合法片段。

继续深挖

  • 允许最多k次下降,用队列保存坏边右端,超过k弹最早坏边并移动left;O(n)时间/O(k)状态。
  • 若要求返回片段,保存最佳(left,right)而非复制每个窗口。
✓已复制微信号!