在问 · 算法题解

665. 非递减数列

题目描述

输入一个长度为 n 的整数数组 nums。

若对所有 0 <= i <= n - 2 都有 nums[i] <= nums[i + 1],就称数组是非递减的。

你最多可以修改一个元素的值(也可以不改)。判断能否借此使数组变为非递减,能则返回 true,否则返回 false。

示例 1
输入:nums = [4,2,3]
输出:true

解释:把开头的 4 改成 1 即可。

示例 2
输入:nums = [4,2,1]
输出:false

解释:无论改哪一个元素,都无法让它变为非递减。

数据范围

  • n == nums.length
  • 1 <= n <= 10^4
  • -10^5 <= nums[i] <= 10^5

解题思路

从左到右找“下降点” nums[i] < nums[i-1]。出现第二个下降点就一定做不到。对第一个下降点,要么把 nums[i-1] 降下来,要么把 nums[i] 升上去。优先降 nums[i-1](改成 nums[i]),这样右边的数最小、对后面最友好;但如果 nums[i] 比 nums[i-2] 还小,降 nums[i-1] 会在 i-2 处产生新的下降,只能把 nums[i] 升到 nums[i-1]。

为什么正确

处理完下标 i 后,经过至多 cnt 次修改的 nums[0..i] 是非递减的,且 nums[i] 是所有可行修改方式中最小的末尾值。

复杂度分析

时间 O(n),空间 O(1)。

易错点

只数下降点个数不够:[3,4,2,3] 只有一个“相邻下降”却做不到;必须真的修改数组,并根据 nums[i-2] 选择修改哪一边。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def checkPossibility(self, nums: List[int]) -> bool:
        cnt = 0
        for i in range(1, len(nums)):
            if nums[i] < nums[i - 1]:
                cnt += 1
                if cnt > 1:
                    return False
                if i >= 2 and nums[i] < nums[i - 2]:
                    nums[i] = nums[i - 1]
                else:
                    nums[i - 1] = nums[i]
        return True

载入编辑器,自己跑一遍 →

数组与矩阵 专题的其他题目

查看 数组与矩阵 全部题目 →