题目
给你一个长度为 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
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。
题解
刚开始我还以为就是单纯的判断是否为递增数列,就没多想。当提交没通过时我有点意外, 【3,4,2,3】,让我很迷惑这题在考察啥?让我迷惑不已。
而这道题考察的是低谷问题,而且解题思路也很简单,你可以抽象为你在马路上走,但是马路上有坑,你见坑填坑不就好啦吗。把坑填啦不就是一条平坦马路啦吗。但是要填几次这就不知道啦。
低谷填坑示例
对于数组构造峰谷折线图
4 1 6 形成低谷,其中 1 为谷底
两端谷峰分别为 4, 6
填平谷底可选取值范围,两端峰值内闭合区域,为了方便,选取两端峰值作为可选填坑值
选取左端峰值作为填坑值
选取右端峰值作为填坑值
那它是选取左端峰值还是右端峰值呢?
选取峰值
1:
你看这种情况,是不是将峰变成谷 将4 变成2
2:
这种情况谷选哪个峰值,不确定的你看下面这张图
这样图毫无疑问的两端都可选,都可以选的前提条件是啥,右峰比左峰高,想上面那种右峰比左峰低那就得选左锋啦
3:
这个图1是谷 2也是谷 4是峰 我们可以将峰变成谷 也就是变成2 变成 【1 2 2 6】和【1 1 2 6】
总结这三张图的规律
1:开局是峰,峰成谷
2:谷峰谷谷, 选左峰
3:谷峰谷峰: 峰边谷
你会发现峰变成谷的情况为 开局就是峰,要吗谷峰谷峰且第二谷大与第一个谷也就是例子3中 2 > 1 但这种可以有两个选择,我们结合第一种峰变谷 峰变成右谷也就是【1 2 2 6】
那吗其余情况就是选左峰
代码实现
/**
* @param {number[]} nums
* @return {boolean}
* 4 2 3
* 3,4,2,3
* 7 1 2 3 5
* -1 4 2 3
* 4 2 1
*/
var checkPossibility = function (nums) {
let total = 1;
for (let i = 1; i <= nums.length - 1; i++) {
const nowNumsItem = nums[i];
const prevNumsItem = nums[i - 1];
if (nowNumsItem < prevNumsItem) {
total--;
if (total < 0) return false;
if (i == 1 || nowNumsItem >= nums[i - 2]) {
nums[i - 1] = nowNumsItem;
} else {
nums[i] = prevNumsItem;
}
}
}
return total >= 0;
};