我的解法
思路
可以很容易想到,输出True的序列一定是在一个原来有序的序列中插入了一个元素导致整个序列出现了一个逆序对,而逆序对无非两种情况。如下图:
- 删除逆序对的第一个元素,则序列有序
- 删除逆序对的第二个元素,则序列有序
因此,只要找到这个逆序对,删除第一个或第二个元素,如果删除某个元素之后序列有序则输出True,否则输出False
class Solution {
public:
bool checkPossibility(vector<int>& nums) {
if (nums.size() < 3) return true;
int unorderIndex = 0;
for (int i = 0; i < nums.size() - 1; i++) {
if (nums[i] > nums[i + 1]) {
unorderIndex = i;
break;
}
}
bool flagA = true;
bool flagB = true;
vector<int> numsBak = nums;
nums.erase(nums.begin() + unorderIndex);
for (int i = 0; i < nums.size() - 1; i++) {
if (nums[i] > nums[i + 1]) {
flagA = false;
break;
}
}
numsBak.erase(numsBak.begin() + unorderIndex + 1);
for (int i = 0; i < numsBak.size() - 1; i++) {
if (numsBak[i] > numsBak[i + 1]) {
flagB = false;
break;
}
}
return (flagA || flagB);
}
};
暴力解法(超时)
对每个元素,使用它的后一个元素覆盖它,再判断覆盖后的序列是不是非减的,一旦出现有序的情况,返回True
这种方法的时间复杂度达到
class Solution(object):
def checkPossibility(self, A):
def monotone_increasing(arr):
for i in range(len(arr) - 1):
if arr[i] > arr[i+1]:
return False
return True
new = A[:]
for i in xrange(len(A)):
old_ai = A[i]
new[i] = new[i-1] if i > 0 else float('-inf')
if monotone_increasing(new):
return True
new[i] = old_ai
return False
官方的解法2/3
说实话,这一题的官方解法我感觉都不太好,我就不放了,有兴趣的可以去
https://leetcode.com/problems/non-decreasing-array/solution/ 看看。
从评论中看到一个讲的比较清楚的做法
题目中给的例子太少,不能覆盖所有情况,我们再来看下面三个例子:
4,2,3
-1,4,2,3
2,3,3,2,4
我们通过分析上面三个例子可以发现,当我们发现后面的数字小于前面的数字产生冲突后,
[1]有时候需要修改前面较大的数字(比如前两个例子需要修改4),
[2]有时候却要修改后面较小的那个数字(比如前第三个例子需要修改2),
那么有什么内在规律吗?是有的,判断修改那个数字其实跟再前面一个数的大小有关系,
首先如果再前面的数不存在,比如例子1,4前面没有数字了,我们直接修改前面的数字为当前的数字2即可。
而当再前面的数字存在,并且小于当前数时,比如例子2,-1小于2,我们还是需要修改前面的数字4为当前数字2;
如果再前面的数大于当前数,比如例子3,3大于2,我们需要修改当前数2为前面的数3。
class Solution {
public boolean checkPossibility(int[] nums) {
if (nums == null || nums.length <= 1) {
return true;
}
int cnt = 0;
for (int i = 1; i < nums.length && cnt < 2; i++) {
if (nums[i-1] <= nums[i]) {
continue;
}
cnt++;
if (i-2>=0 && nums[i-2] > nums[i]) {
nums[i] = nums[i-1];
}else {
nums[i-1] = nums[i];
}
}
return cnt <= 1;
}
}