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 0≤i≤n−2),均满足 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[i−1]。令 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[i−1] 成立,也即是 n u m s [ i + 1 ] ≥ n u m s [ i − 1 ] nums[i+1] \geq nums[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 + 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)。
欢迎关注
公众号 【书所集录】
如有错误,烦请指出,欢迎指点交流。若觉得写得还不错,麻烦点个赞👍,谢谢。