LeetCode上非递减数列,看上去是简单题,但是挺难想的,这里有个图解说的挺详细的图解证明:最多一个「峰谷」落差,参考这篇文章的思路
参考上文的思路,假设数组是递增的,那么每次出现非递增的数字的时候,就会出现一个[谷],所以题意是求只有一个[谷]的情况
- 从数组两头开始遍历,分别确认为连续非递减数列,当出现为非递增的情况,指针停下,记住当前位置
- 如果停下来的时候,left和right中间的差值大于1,那么就相当于中间起码有2个以上的[谷]就不满足条件
- 在考虑如果[谷]出现在首尾的情况,直接更改就可以实现非递减
- 如果只存在一个[谷]还需要判断,这个[谷]是否通过交换能够实现非递增
前面3点都还好理解,第4点可以看这个例子,现在传入[3,4,2,3]
,通过左右2个指针来看可以得到left = 1,right=2
,在这个[4,2]
之间出现了一个[谷]
如果将2替换为5,满足[3,4,5]的递增,但是[4,5,3]就不满足了,那么可以确定这样替换是不满足条件的。
var checkPossibility = function(nums) {
// 设定2个指针,从左右开始扫描数组
let right = nums.length - 1
let left = 0
// 从左开始扫描数组
while(left < nums.length - 1 && nums[left + 1] >= nums[left]) {
// 当在数组范围且后一位大于等于前一位的时候,left指针右移
left = left + 1
}
// 从右侧开始扫描数组
while(right > 0 && nums[right] >= nums[right - 1]) {
// 当在数组范围且当前位大于等于前一位的情况,right指针左移
right = right - 1
}
console.log(left,right);
// 如果左右都能走到头的情况,那么就是非递减数组
if(right === 0 && left === nums.length - 1) return true
// 如果左右差距1,那么就代表起码存在2个以上的[谷]
if(right - left > 1) return false
// 如果[谷]在数组首尾的情况,直接更改就可以
if(right === nums.length - 1 || left === 0) return true
// 查到了只有一个[谷],那么要看能否交换
if(nums[right+1] >= nums[left] || nums[left-1] <= nums[right]) return true
// 如果以上都不满足,就返回false
return false
};