非递减数列(算法题)
题目:给你一个长度为 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
思路
假设有两个不同的下标 i, j满足上述不等式,不妨设 i<j。
若 i+1<j,则无论怎么修改 nums[i]或nums[i+1],都不会影响 nums[j]与 nums[j+1]之间的大小关系;修改 nums[j] 或nums[j+1] 也同理。因此,这种情况下,我们无法将nums 变成非递减数列。
若i+1=j,则有 nums[i]>nums[i+1]>nums[i+2]。同样地,无论怎么修改其中一个数,都无法使这三个数变为 nums[i]≤nums[i+1]≤nums[i+2] 的大小关系。
因此,上述问题的结论是:
至多一个。
满足这个条件就足够了吗?并不,对于满足该条件的数组 3,4,1,2[3,4,1,2] 而言,无论怎么修改也无法将其变成非递减数列。
因此,若找到了一个满足 nums[i]>nums[i+1]的 i,在修改 nums[i]或 nums[i+1]之后,还需要检查 nums 是否变成了非递减数列。
我们可以将 nums[i] 修改成小于或等于 nums[i+1]的数,但由于还需要保证 nums[i]不小于它之前的数,nums[i]越大越好,所以将 nums[i]修改成 nums[i+1] 是最佳的;同理,对于 nums[i+1],修改成 nums[i] 是最佳的。
class Solution {
public:
bool checkPossibility(vector<int> &nums) {
int n = nums.size();
for (int i = 0; i < n - 1; ++i) {
int x = nums[i], y = nums[i + 1];
if (x > y) {
nums[i] = y;
if (is_sorted(nums.begin(), nums.end())) {
return true;
}
nums[i] = x; // 复原
nums[i + 1] = x;
return is_sorted(nums.begin(), nums.end());
}
}
return true;
}
};