【一次遍历】LeetCode 665. 非递减数列

665. 非递减数列


题目


给你一个长度为 n 的整数数组,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。

我们是这样定义一个非递减数列的: 对于数组中所有的 i (0 <= i <= n-2),总满足 nums[i] <= nums[i + 1]

示例 1:

输入: nums = [4,2,3]
输出: true
解释: 你可以通过把第一个4变成1来使得它成为一个非递减数列。

示例 2:

输入: nums = [4,2,1]
输出: false
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。

说明:

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

解题思路


标签:数组

先审题,题目给定一个长度为 n n n 的整数数组 n u m s nums nums

题目要求:

  • 判断在 最多 改变 1 个元素的情况下,使得数组 n u m s nums nums 变成一个非递减数列。

其中 非递减数列 的定义:

  • 对于数组中所有的 i i i 0 ≤ i ≤ n − 2 0 \leq i \leq n-2 0in2),均满足 n u m s [ i ] ≤ n u m s [ i + 1 ] nums[i] \leq nums[i+1] nums[i]nums[i+1]

那么现在的问题是 ,原数组在什么样的情况下,才能 最多 改变 1 个元素,使得数组变为一个非递减数列?

这里先说下结论:原数组中最多存在一处 n u m s [ i ] > n u m s [ i + 1 ] nums[i] > nums[i+1] nums[i]>nums[i+1] 的情况。举个反例:

假设存在 i i i,使得 n u m s [ i ] > n u m s [ i + 1 ] > n u m s [ i + 2 ] nums[i] > nums[i+1] > nums[i+2] nums[i]>nums[i+1]>nums[i+2],在这个不等式中,存在两处前面元素大于后面元素的情况,我们可以发现,无论修改哪个元素,都无法使得上面不等式变为非递减的关系。

也就说,我们可以通过判断数组中存在 n u m s [ i ] > n u m s [ i + 1 ] nums[i] > nums[i+1] nums[i]>nums[i+1] 的情况有多少处,进而来判断是否能够最多改变 1 个元素,使得数组变为非递减数列。

上面的结论作为前提是正确的。但是,这里需要注意一个问题。当修改数组中的某处元素之后,元素值发生改变,会影响后续元素的值大小比较,所以修改值后,还必须继续检查数组是否是非递减数列。

例如下面的数组:

输入:[3, 4, 1, 2]

在这个数字中,只存在 4 > 1 4 > 1 4>1 一处递减的情况,但是这个示例,无论修改哪个元素,都无法使得数组变为非递减数列。

同时这里说一下,当确定修改元素值时,应该将元素值修改为多少?

假设要修改 n u m s [ i ] nums[i] nums[i],必须确保修改后 n u m s [ i ] ≥ n u m s [ i − 1 ] nums[i] \geq nums[i-1] nums[i]nums[i1]。令 a = n u m s [ i ] a = nums[i] a=nums[i] b = n u m s [ i + 1 ] b = nums[i+1] b=nums[i+1],那么这个修改值应该落在区间 ( a , b ] (a, b] (a,b],而 n u m s [ i ] nums[i] nums[i] 应该尽可能取大值 b b b,也就是取 n u m s [ i + 1 ] nums[i+1] nums[i+1]

同样,当要修改 n u m s [ i + 1 ] nums[i+1] nums[i+1] 时,要确保修改后的 n u m s [ i + 1 ] nums[i+1] nums[i+1] 小于或等于后面的值,那么 n u m s [ i + 1 ] nums[i+1] nums[i+1] 应该尽可能取小值,这里 n u m s [ i ] nums[i] nums[i] 为可取的最小值。

那么现在需要的考虑的问题是,当原数组出现一处递减的情况时(假设 n u m s [ i ] > n u m s [ i + 1 ] nums[i] > nums[i+1] nums[i]>nums[i+1]),这里应该修改 n u m s [ i ] nums[i] nums[i] 还是 n u m s [ i + 1 ] nums[i+1] nums[i+1]?下面我们分情况来讨论下:

  • 如果要修改 n u m s [ i ] nums[i] nums[i] 的值,根据前面所述,令 n u m s [ i ] = n u m s [ i + 1 ] nums[i] = nums[i+1] nums[i]=nums[i+1],这里必须确保 n u m s [ i ] ≥ n u m s [ i − 1 ] nums[i] \geq nums[i-1] nums[i]nums[i1] 成立,也即是 n u m s [ i + 1 ] ≥ n u m s [ i − 1 ] nums[i+1] \geq nums[i-1] nums[i+1]nums[i1] 要成立,否则应该考虑修改 n u m s [ i + 1 ] nums[i+1] nums[i+1] 的值;
  • 当修改 n u m s [ i ] nums[i] nums[i] 的值不满足条件时,考虑修改 n u m s [ i + 1 ] nums[i+1] nums[i+1] 的值为 n u m s [ i ] nums[i] nums[i],然后继续对后续的元素值进行大小比较。

上面是针对一处递减情况的分析,在遍历数组的过程中,我们可以用 c o u n t count count 来存储 n u m s [ i ] > n u m s [ i + 1 ] nums[i] > nums[i+1] nums[i]>nums[i+1] 出现的次数,当次数大于 1 次时,可以直接返回 F a l s e False False

具体代码实现如下。

class Solution:
    def checkPossibility(self, nums: List[int]) -> bool:
        n = len(nums)
        # 存储 nums[i] > nums[i+1] 出现的次数
        count = 0
        for i in range(n - 1):
            if nums[i] > nums[i + 1]:
                count += 1
                # count > 1 时,可直接返回 False
                if count > 1:
                    return False
                # 出现递减的情况时,若 nums[i+1] < nums[i-1] ,表示修改 nums[i] 的值为 nums[i+1] 时无法满足非递减关系,考虑修改 nums[i+1] 的值为 nums[i],继续对后续元素大小判断
                # 因为题目不要求返回具体的修改方案,当修改 nums[i] 能够满足条件时,可先不作处理。
                # 因为当遍历过程中 count 大于 1 时,直接返回 False。
                # 若遍历完成 count 小于或等于 1,那么 nums[i] 修改为 nums[i+1] 即可。
                if i > 0 and nums[i + 1] < nums[i - 1]:
                    nums[i + 1] = nums[i]
        
        return True

复杂度分析:

  • 时间复杂度 O ( n ) O(n) O(n) n n n 表示数组的长度。
  • 空间复杂度 O ( 1 ) O(1) O(1)

欢迎关注


公众号 【书所集录


如有错误,烦请指出,欢迎指点交流。若觉得写得还不错,麻烦点个赞👍,谢谢。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值