题目描述:
我们定义 arr
是 山形数组 当且仅当它满足:
给你整数数组 nums
,请你返回将 nums
变成 山形状数组 的 最少 删除次数。
数据范围:
3≤nums.len≤1000,1≤nums[i]≤109
题解:
可以发现是一个单调上升子序列问题,而且是严格上升。只需要找一下以每个位置结尾的单调上升子序列的长度即可。
刚好可以左边一遍,右边一遍。
可以选择使用二分的做法, dp[len] 表示长度为 len 的子序列末尾最小数字,然后对于 nums[i] 如果可以直接接在 dp[len] 末尾,那么就 dp[++len] = nums[i]
。不能接的话说明 nums[i]<dp[len] ,可以从前面找出来末尾字符比 nums[i] 大的,使用 lower_bound(dp+1,dp+1+len+1,nums[i]) 找到下标 index ,然后修改长度为 index 的末尾数字为 nums[i] 。
最后需要注意的是,最后的数组的长度要大于等于 3 ,而且需要满足,山峰不在左右端点处,因此需要判断 left[i]>1 , right[i]>1 。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| auto optimize_cpp_stdio = []() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); std::cout.tie(nullptr); return 0; }(); class Solution { public: const static int maxn = 1e5 + 10; const static int maxm = 1e5 + 10; const int INF = 0x3f3f3f3f; int minimumMountainRemovals(vector<int> &nums) { int n = nums.size(); vector<int> left(n), right(n); vector<int> a(n); a[0] = nums[0]; int len = 1; left[0] = len; for (int i = 1; i < n; ++i) { if (nums[i] > a[len - 1]) a[len++] = nums[i]; else { int index = lower_bound(a.begin(), a.begin() + len, nums[i]) - a.begin(); a[index] = nums[i]; } left[i] = len; }
len = 1; right[n - 1] = len; a[0] = nums[n - 1]; for (int i = n - 2; i >= 0; --i) { if (nums[i] > a[len - 1]) a[len++] = nums[i]; else { int index = lower_bound(a.begin(), a.begin() + len, nums[i]) - a.begin(); a[index] = nums[i]; } right[i] = len; } int ans = n; for (int i = 1; i < n - 1; ++i) { if (left[i] > 1 && right[i] > 1) { ans = min(ans, n - left[i] - right[i] + 1); } } return ans; } };
|
v1.5.1