给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 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
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
思路一:
对数组进行遍历,如果遇到nums[i] > nums[i+1]那么就是必须要进行调整的。
调整无非就是有二个方法:
- 方法一:把nums[i]改小变成nums[i+1],但是又不能小于nums[i-1];所以
要求nums[i+1]必须大于或者等于nums[i-1],如果nums[i+1]<nums[i-1]那么就是肯定怎么改都不和题意了,直接返回False - 方法二:把nums[i+1]改大变成nums[i],但是又不能大于nums[i+2]。所以
要求nums[i]必须小于或者等于nums[i+2],如果nums[i]大于nums[i+2]那么就是肯定怎么改都不和题意了,直接返回False - 边界情况:当i==0,也就是处理数组第一个和第二个元素的时候,那么肯定是怎么改都不会小于nums[i-1]的了,所以直接nums[i]改小为nums[i+1]
- 当处理数组倒数第二个和倒数第一个元素的时候,也是怎么改大都不会大于i+2了,所以直接nums[i+1]改大为nums[i]
举例说明:
比如 2,8,5,6 这种,我们就只能选择方法一把8改小变成5,因为如果选择方法二,就变成2,8,8,6,就不对了,应该是2,5,5,6才对
比如 2,8,1,9 这种,我们就只能选择方法二把1改成8,因为如果选择方法一,就变成2,1,1,9就不对了,应该是2,8,8,9才对
其他的情况,比如 2,8,1,6 这种,或者 2,8,6,7就是False,怎么改都不行了
思路二:
如果存在i,使的nums[i+1]<nums[i],我们就说出现了一次“下降”
分3种情况:
1、不存在下降的情况,即下降次数为0,返回true。
2、只出现了1次下降,将下降后的元素记为nums[x](1=<x<n)
此时,可以将nums[x-1]变小,或将nums[x]变大,以达到“非递减”的目的。
- 如果x=1或者x=n-1,只需要将nums中第一个元素减小(最差到Integer.MIN_VALUE),或者最后一个元素增大总能满足要求;
- 如果1<x<n-1,若将nums[x]变大必须要求nums[x-1]<=nums[x+1];
- 若将nums[x-1]变小,须要求nums[x-2]<=nums[x];
3、出现超过1次的下降,肯定不同只通过调整一个元素完成要求,返回false。
整体代码:
public boolean checkPossibility(int[] nums) {
int n = nums.length;
if (n <= 1) return true;
int down = 0;
for (int i = 1; i < n; i++) {
if (nums[i] < nums[i - 1]) {
down++;
if (down > 1) {
return false;
}
if (i > 1 && i < n - 1 && nums[i - 1] > nums[i + 1] && nums[i - 2] > nums[i]) {
return false;
}
}
}
return true;
}