SWE · Coding

至多改一个整数的最长单调子段:严格与非降两个版本

分别处理a<b和a≤b,连接左右段的整数可行条件不同。

题目重点:分别处理a<b和a≤b,连接左右段的整数可行条件不同。

题意与假设

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

  • 值为无界整数,只能修改至多一个位置;返回连续子段长度,不是子序列。
  • strict=True要求严格递增,对应严格版本;False采用非降重建版本。AI重建文本的细则不能当统一合同。

解题路线

  1. left[i]/right[i]分别为不修改时以i结束/开始的最长合法段。保留不改的最大值。
  2. 假设改i,可以延伸左段+新值,也可以新值+右段,无界整数总能单边满足。要同时桥接,需要选整数x满足a[i−1]<x<a[i+1],即右−左≥2;非降只需左≤右。
  3. 枚举每个修改点取max(left+1,right+1,left+right+1若可桥接)。最优修改段要么含改点且只向一侧伸展,要么两侧都伸展,枚举完整。

手动走一遍

[1,2,100,4,5]改100为3得到长5。若邻值2和3严格版无中间整数,不能桥接;非降版可选2或3。空数组0,单元素1;“必须修改”若允许改为同值需再确认。

Python 参考实现

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

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

def longest_one_change(a, strict=True):
    n=len(a)
    if not n:return 0
    def ordered(x,y):return x<y if strict else x<=y
    left=[1]*n;right=[1]*n
    for i in range(1,n):
        if ordered(a[i-1],a[i]):left[i]=left[i-1]+1
    for i in range(n-2,-1,-1):
        if ordered(a[i],a[i+1]):right[i]=right[i+1]+1
    answer=max(left)
    for i in range(n):
        l=left[i-1] if i else 0;r=right[i+1] if i+1<n else 0
        answer=max(answer,l+1,r+1)
        if i and i+1<n and (a[i+1]-a[i-1]>=2 if strict else a[i-1]<=a[i+1]):
            answer=max(answer,l+1+r)
    return answer

复杂度

O(n)时间、O(n)空间;需要返回修改值/下标时保存最优方案与合同边界。

易错点与追问

容易失分的边界

  • 浮点数域只要left<right便可能桥接,不能沿用整数差≥2。
  • 非降允许重复,不能把严格版本代码无条件用于AI重建描述。

继续深挖

  • 值还有限定上下界时单侧延伸何时失效?
  • 允许改两次,怎样定义状态或使用区间可行性?
✓已复制微信号!