跳到主要内容

665. 非递减数列

1. 题目简介​

难度:中等,原题链接:665. 非递减数列。

给你一个长度为 n 的整数数组 nums ,请你判断在 最多 改变 1 个元素的情况下,该数组能否变成一个非递减数列。

2. 问题分析​

非递减数列是指每个元素都不大于后一个元素,即所有相邻位置都满足 nums[i] <= nums[i + 1]。

找到第一处 nums[i] > nums[i + 1] 后,只需尝试修改这两个元素之一。因为修改其他位置无法消除这一对元素的逆序,而题目最多允许修改一次。

两种选择都可能有用:

  • [1, 2, 1, 1] 需要降低下标 1 的值,得到 [1, 1, 1, 1]。如果提高后一个 1,后面仍然会出现逆序。
  • [3, 4, 2, 5] 需要提高下标 2 的值,得到 [3, 4, 4, 5]。如果只降低 4,它既要不小于前面的 3,又要不大于后面的 2,无法同时满足。

代码分别尝试修改下标 i 和 i + 1。对于待修改的位置,有前驱时就把它设为前驱的值,这是保持左侧非递减所允许的最小值,也给右侧留下了最大的选择范围。修改头部时没有前驱,代码使用 Integer.MIN_VALUE。

每次尝试后都重新检查整个数组,并恢复被修改的值,避免影响下一次尝试。如果两种选择都失败,就无法只改一个元素完成;如果原数组没有逆序,则直接返回 true。

3. 代码实现​

class Solution {
public boolean checkPossibility(int[] nums) {
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i] > nums[i + 1]) {
return check(nums, i) || check(nums, i + 1);
}
}
return true;
}

private boolean check(int[] nums, int i) {
int tmp = nums[i];
nums[i] = i == 0 ? Integer.MIN_VALUE : nums[i - 1];
boolean flag = true;
for (int j = 0; j < nums.length - 1; j++) {
if (nums[j] > nums[j + 1]) {
flag = false;
break;
}
}
nums[i] = tmp;
return flag;
}
}

4. 复杂度分析​

  • 时间复杂度:O(n)。寻找第一处逆序后,最多再做两次完整检查,扫描次数是常数。
  • 空间复杂度:O(1)。

来源:Coding 101 原文 · 免费阅读,引用请保留出处。内容使用说明