Medium
题目描述
给定一个整数数组 nums。
你需要从 nums 中移除恰好一个前缀(可能为空)。
返回一个整数,表示使剩余数组严格递增所需移除的最小前缀长度。
示例 1:
输入:nums = [1,-1,2,3,3,4,5]
输出:4
解释:
移除前缀 [1, -1, 2, 3] 后,剩余数组 [3, 4, 5] 严格递增。
示例 2:
输入:nums = [4,3,-2,-5]
输出:3
解释:
移除前缀 [4, 3, -2] 后,剩余数组 [-5] 严格递增。
示例 3:
输入:nums = [1,2,3,4]
输出:0
解释:
数组 nums = [1, 2, 3, 4] 已经严格递增,所以移除空前缀即可。
约束条件:
1 <= nums.length <= 10^5-10^9 <= nums[i] <= 10^9
提示:
- 从右边找到第一个索引
i,使得nums[i] >= nums[i + 1]。 - 如果存在这样的索引,答案是
i + 1;否则,数组已经严格递增。
解题思路
解题思路
这道题的关键在于理解题意:我们需要找到最小的前缀长度,移除后剩余的数组严格递增。
核心观察: 如果数组已经严格递增,则不需要移除任何前缀。如果不是严格递增,那么从右往左找到第一个不满足严格递增条件的位置,移除到该位置为止的所有元素即可。
算法步骤:
- 从数组末尾开始向前遍历
- 找到第一个位置
i,使得nums[i] >= nums[i+1](违反严格递增) - 如果找到这样的位置,说明需要移除前
i+1个元素 - 如果没找到,说明数组已经严格递增,返回 0
时间复杂度分析: 最坏情况下需要遍历整个数组一次,时间复杂度为 O(n)。
空间复杂度分析: 只使用常数额外空间,空间复杂度为 O(1)。
这是一个贪心算法,因为我们总是希望保留尽可能多的元素,所以从右边开始找到第一个破坏严格递增性质的位置就是最优解。
代码实现
class Solution {
public:
int minimumPrefixLength(vector<int>& nums) {
int n = nums.size();
// 从右往左找第一个不满足严格递增的位置
for (int i = n - 2; i >= 0; i--) {
if (nums[i] >= nums[i + 1]) {
return i + 1;
}
}
// 数组已经严格递增
return 0;
}
};
class Solution:
def minimumPrefixLength(self, nums: List[int]) -> int:
n = len(nums)
# 从右往左找第一个不满足严格递增的位置
for i in range(n - 2, -1, -1):
if nums[i] >= nums[i + 1]:
return i + 1
# 数组已经严格递增
return 0
public class Solution {
public int MinimumPrefixLength(int[] nums) {
int n = nums.Length;
// 从右往左找第一个不满足严格递增的位置
for (int i = n - 2; i >= 0; i--) {
if (nums[i] >= nums[i + 1]) {
return i + 1;
}
}
// 数组已经严格递增
return 0;
}
}
var minimumPrefixLength = function(nums) {
const n = nums.length;
// 从右往左找第一个不满足严格递增的位置
for (let i = n - 2; i >= 0; i--) {
if (nums[i] >= nums[i + 1]) {
return i + 1;
}
}
// 数组已经严格递增
return 0;
};
复杂度分析
| 复杂度 | 分析 |
|---|---|
| 时间复杂度 | O(n) - 最坏情况下需要遍历整个数组 |
| 空间复杂度 | O(1) - 只使用常数额外空间 |