leetcode每日一题之665. 非递减数列
本题虽然说是简单题,但是并不简单,bebug了数十次,没看错,确实是数十次,才ac。有种面向测试用例编程的感觉了。
好在最后提交的总体思路和官方题解差不多,也不枉我熬一宿了,是的,这个题目做了好久的。不过相对官方题解,有不少的冗余,在注释里会提到。
大体思路就是每次遇到一组前大后小的两个数,就记录一下,然后对其进行处理(这是关键),如果遇到第二次这样的情况,那就说明不能通过一次修改将其变为非递减序列,返回false。
要对这两个数进行处理,就要考虑,是处理改变前一个数还是改变后一一个数,什么情况下怎么改变;由于我们一直比较的是前后两个数,如果是前一个数需要修改,那么对后续的比较不产生影响,就不做处理,因此我们只考虑后一个数需要被修改的情况。
因为我们修改之后要保证前后这两数是非递减,比如当前不符合条件的两个数是a[i]和a[i+1],因为修改之后不能破坏a[i-1]和a[i]的非递减关系,如果a[i-1]大于a[i+1],那么只能将a[i+1]置为a[i],如果将a[i]修改为a[i+1],则破坏了a[i-1]和a[i]的非递减关系。另一种情况,如果a[i-1]小于等于a[i+1],此时为了尽可能保持后面是递增序列,则a[i+1]要尽可能小,所以不能增大a[i+1],所以将a[i]修改为a[i+1]或者a[i-1]比较合适,更准确的话,a[i]也要尽可能小,但是a[i]已经不会对后面的结果造成影响,因为以后就是a[i+1]以后的比较了。
综上,我们只需要考虑需要修改a[i+1]的情况,并且确定如何修改a[i+1]
代码如下
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
int n = nums.size();
// if(n < 3)
// return true; // 此前代码中有a[2],所以要将长度小于3的数组直接返回
// if(n == 3)
// if(nums[0] > nums[1] && nums[1] > nums[2])
// 如果开头有连续三个递减,则直接返回false
// return false;
int count = 0;
for(int i = 0; i < n - 1; i++)
if(nums[i] > nums[i + 1])
count++;
if(count > 1)
return false;
if(i > 0) // 如果第0和第1两位逆序,不进行操作,后面再出现一个逆序就为false
// 因为第0个数取值取决于后面,整个序列能否非递减也是取决于后面
// 如果是第1位和后面出现逆序,需要操作一次,后面再出现一个逆序就为false
if(nums[i - 1] > nums[i + 1])
nums[i + 1] = nums[i];
// else
// nums[i] = nums[i - 1]; // 可以不处理
// else // i等于0的时候,如果a[0]>a[1],肯定是将a[0]置为a[1],修改a[0]对后面的判断没有影响,所以不需要操作
// if(nums[0] > nums[2])
// nums[0] = nums[1];