665. 非递减数列
1. 题目简介
难度:中等,原题链接:665. 非递减数列。
给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。
2. 问题分析
通过对题目的分析,我们可以发现这道题包含两个子问题:
- 判断当前数组是否是一个非递减数组
- 如果不是非递减数组,修改
1
个元素,使其变为非递减数组
让我们依次分析这两个条件。
- 判断非递减数组
对于一个数列中,如果存在至少一个 i
满足 nums[i]
> nums[i + 1]
,则表示当前数列不是一个非递减数列。题目中规定最多改变 1
个元素,则找到第一个符合条件的 i
即可。
- 修改
1
个元素,使数组变为非递减数组
当存在 nums[i] > nums[i + 1]
时,根据数组的值,我们需要判断修改的元素是 nums[i]
还是 nums[i + 1]
。
- 调整
nums[i]
的情况:考虑数列[1, 2, 1, 1]
,当i = 1
时有nums[i] > nums[i + 1]
,此时需要使nums[1] = 1
才能保证非递减数列; - 调整
nums[i + 1]
的情况:考虑数列[1, 2, 1, 2]
,当i = 1
时有nums[i] > nums[i + 1]
,此时需要调整nums[2] = 2
才能保证非递减数列。
因此,我们需要分别判断修改 nums[i]
还是 nums[i + 1]
才能保证非递减数组成立。
此时还有一个引申的问题,就是如何修改指定元素。对于一个非递减数组,对于 nums[i]
存在 nums[i - 1] <= nums[i] <= nums[i + 1]
,可以考虑将 nums[i]
修改为下界 nums[i - 1]
或者上界 nums[i + 1]
。对于边界情况,可以直接赋最大值或者最小值即可。本题解选择修改为下界。
修改后,还需要校验修改后的数组是否为一个非递减数组,遍历修改后的数组即可。
3. 代码实现
class Solution {
public boolean checkPossibility(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] > nums[i + 1]) {
return check(nums, i) || check(nums, i + 1);
}
}
return true;
}
private boolean check(int[] nums, int i) {
int tmp = nums[i];
nums[i] = i == 0 ? Integer.MIN_VALUE : nums[i - 1];
boolean flag = true;
for (int j = 0; j < nums.length - 1; j++) {
if (nums[j] > nums[j + 1]) {
flag = false;
break;
}
}
nums[i] = tmp;
return flag;
}
}
4. 复杂度分析
- 时间复杂度:O(n),需要遍历数组,确定是否为非递减数组。
- 空间复杂度:O(1)。