Leetcode(665)——非递减数列

探讨如何在最多修改一个元素的情况下,判断整数数组能否转化为非递减序列。算法涉及贪心策略,通过遍历一次查找冲突位置并调整元素,确保满足非递减条件。

Leetcode(665)——非递减数列

题目

给你一个长度为 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
解释: 你不能在只改变一个元素的情况下将其变为非递减数列。

提示:

  • n == nums.length
  • 1 <= n <= 104
  • -105 <= nums[i] <= 105

题解

方法一:贪心算法

思路

​​  首先思考如下问题:要使数组 nums\textit{nums}nums 变成一个非递减数列,数组中最多有多少个 iii 满足 nums[i]>nums[i+1]\textit{nums}[i]>\textit{nums}[i+1]nums[i]>nums[i+1]

最多一个。

​​  假设有两个不同的下标 iii, jjj 满足上述不等式,不妨设 i<ji<ji<j

  1. i+1<ji+1<ji+1<j,则无论怎么修改 nums[i]\textit{nums}[i]nums[i]nums[i+1]\textit{nums}[i+1]nums[i+1],都不会影响 nums[j]\textit{nums}[j]nums[j]nums[j+1]\textit{nums}[j+1]nums[j+1] 之间的大小关系;修改 nums[j]\textit{nums}[j]nums[j]nums[j+1]\textit{nums}[j+1]nums[j+1] 也同理。因此,这种情况下,我们无法将 nums\textit{nums}nums 变成非递减数列。
  2. i+1=ji+1=ji+1=j,则有 nums[i]>nums[i+1]>nums[i+2]\textit{nums}[i]>\textit{nums}[i+1]>\textit{nums}[i+2]nums[i]>nums[i+1]>nums[i+2]。同样地,无论怎么修改其中一个数,都无法使这三个数变为 nums[i]≤nums[i+1]≤nums[i+2]\textit{nums}[i]\le\textit{nums}[i+1]\le\textit{nums}[i+2]nums[i]nums[i+1]nums[i+2] 的大小关系。

​​  满足这个条件就足够了吗?并不,对于满足该条件的数组 [3,4,1,2][3,4,1,2][3,4,1,2] 而言,无论怎么修改也无法将其变成非递减数列。
​​  因此,若找到了一个满足 nums[i]>nums[i+1]\textit{nums}[i]>\textit{nums}[i+1]nums[i]>nums[i+1]iii,在修改 nums[i]\textit{nums}[i]nums[i]nums[i+1]\textit{nums}[i+1]nums[i+1] 之后,还需要检查 nums\textit{nums}nums 是否变成了非递减数列。

​​  我们可以将 nums[i]\textit{nums}[i]nums[i] 修改成小于或等于 nums[i+1]\textit{nums}[i+1]nums[i+1] 的数,但由于还需要保证 nums[i]\textit{nums}[i]nums[i] 不小于它之前的数,nums[i]\textit{nums}[i]nums[i] 越大越好,所以将 nums[i]\textit{nums}[i]nums[i] 修改成 nums[i+1]\textit{nums}[i+1]nums[i+1] 是最佳的;同理,对于 nums[i+1]\textit{nums}[i+1]nums[i+1],修改成 nums[i]\textit{nums}[i]nums[i] 是最佳的。

能否只遍历一次遍历 nums\textit{nums}nums 数组呢?
​​  修改 nums[i]\textit{nums}[i]nums[i]nums[i+1]\textit{nums}[i+1]nums[i+1] 后,还需要保证 nums[i−1]≤nums[i]\textit{nums}[i-1]\le\textit{nums}[i]nums[i1]nums[i] 仍然成立,即 nums[i−1]≤nums[i+1]\textit{nums}[i-1]\le\textit{nums}[i+1]nums[i1]nums[i+1],若该不等式不成立则整个数组必然不是非递减的,则需要修改 nums[i+1]\textit{nums}[i+1]nums[i+1]nums[i]\textit{nums}[i]nums[i]。修改完后,接着判断后续数字的大小关系。在遍历中统计 nums[i]>nums[i+1]\textit{nums}[i]>\textit{nums}[i+1]nums[i]>nums[i+1] 的次数,若超过一次可以直接返回 false\text{false}false

代码实现
class Solution {
public:
    bool checkPossibility(vector<int>& nums) {
        // 1.找到第一对导致序列为非递减的两个值(前者大于后者),找不到则返回true
        // 2.找到第一对导致序列为非递减的两个值,判断第一个值的前者是否小于等于第二个值,若为true则继续,若为false则
        // 判断第一个值是否小于等于第二个值的后者,若为true则继续,否则返回false
        // 3.再判断后序列是否都为非递减数列,即能否找到第二对导致序列为非递减的两个值,找到返回false,否则返回true
        int size = nums.size(), non_value = 0;  // non_value 表示导致序列为非递减地方的个数
        if(size <= 2) return true;  // 若小于等于2,则一定可以在最多改变1个元素的情况下使得该数组变成一个非递减数列
        for(int n = 1; n < size; n++){
            if(nums[n-1] > nums[n]){
                // 非递减的两个值
                if(++non_value <= 1) {
                    // 还要注意是否是 n-1 是否是第一个值和 n 是否是最后一个值的特殊情况
                    if(n == 1 || nums[n-2] <= nums[n] || n == size-1 || nums[n-1] <= nums[n+1]) continue;
                    else return false;
                }else return false;
            }
        }
        return true;
    }
};
复杂度分析

时间复杂度O(n)O(n)O(n),其中 nnn 是数组 nums\textit{nums}nums 的长度。
空间复杂度O(1)O(1)O(1)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值