|
| 1 | +## 题目地址(168. Longest Contiguously Strictly Increasing Sublist After Deletion) |
| 2 | + |
| 3 | +https://binarysearch.com/problems/Longest-Contiguously-Strictly-Increasing-Sublist-After-Deletion |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +Given a list of integers nums, return the maximum length of a contiguous strictly increasing sublist if you can remove one or zero elements from the list. |
| 9 | +
|
| 10 | +Constraints |
| 11 | +
|
| 12 | +n ≤ 100,000 where n is the length of nums |
| 13 | +Example 1 |
| 14 | +Input |
| 15 | +nums = [30, 1, 2, 3, 4, 5, 8, 7, 22] |
| 16 | +Output |
| 17 | +7 |
| 18 | +Explanation |
| 19 | +If you remove 8 in the list you can get [1, 2, 3, 4, 5, 7, 22] which is the longest, contiguous, strictly increasing list. |
| 20 | +``` |
| 21 | + |
| 22 | +## 前置知识 |
| 23 | + |
| 24 | +- 动态规划 |
| 25 | + |
| 26 | +## 思路 |
| 27 | + |
| 28 | +出这道题就是为了让大家明白一点**对于连续性的 DP 问题通常我们的策略都是一层循环 + 一维 DP(有时候可滚动数组优化)**。比如今天这个题。 |
| 29 | + |
| 30 | +动态规划问题的关键就是:假设部分子问题已经解决了,并仅仅考虑局部,思考如何将已解决的子问题变成更大的子问题,这样就相当于向目标走进了一步。 |
| 31 | + |
| 32 | +我们可以定义状态: |
| 33 | + |
| 34 | +- dp[i][0] 表示以 nums[i] 结尾的删除 0 个数的情况下的最长严格递增子数组。 |
| 35 | +- dp[i][1] 表示以 nums[i] 结尾的删除 1 个数的情况下的最长严格递增子数组。 |
| 36 | + |
| 37 | +> 你也可定义两个一维数组,而不是一个二维数组。比如 dp0[i] 表示以 nums[i] 结尾的删除 0 个数的情况下的最长严格递增子数组。dp1[i] 表示以 nums[i] 结尾的删除 1 个数的情况下的最长严格递增子数组 |
| 38 | +
|
| 39 | +接下来,我们需要分情况讨论。 |
| 40 | + |
| 41 | +- 如果 nums[i] > nums[i-1],那么 dp[i][0] 和 dp[i][1] 都可以在前一个的基础上 + 1。也就是: |
| 42 | + |
| 43 | +```py |
| 44 | +dp[i][0] = dp[i-1][0] + 1 |
| 45 | +dp[i][1] = dp[i-1][1] + 1 |
| 46 | +``` |
| 47 | + |
| 48 | +- 否则 dp[i][0] = dp[i][1] = 1 |
| 49 | + |
| 50 | +最终返回遍历过程中的 dp[i][0] 和 dp[i][1] 的最大值,用一个变量记录即可。 |
| 51 | + |
| 52 | +上面的算法少考虑了一个问题,那就是如果 nums[i] > nums[i-2],我们其实可以选择 nums[i-1],转而和 dp[i-2] 产生联系。也就是 dp[i][1] = dp[i-2][0] + 1。这个 1 就是将 nums[i-1] 删掉的一个操作。 |
| 53 | + |
| 54 | +需要注意的是判断 nums[i] > nums[i-2] 不是在 nums[i] <= nums[i-1] 才需要考虑的。 比如 [1,2,3.0,4] 这种情况。当遍历到 4 的时候,虽然 4 > 0,但是我们不是和 dp[i-1] 结合,这样答案就小了,而是要和 nums[i-2] 结合。 |
| 55 | + |
| 56 | +扩展一下,如果题目限定了最多删除 k 个呢? |
| 57 | + |
| 58 | +- 首先状态中列的长度要变成 k |
| 59 | +- 其次,我们往前比较的时候要比较 nums[i-1], nums[i-2], ... , nums[i-k-1],取这 k + 1 种情况的最大值。 |
| 60 | + |
| 61 | +## 关键点 |
| 62 | + |
| 63 | +- 连续性 DP |
| 64 | + |
| 65 | +## 代码 |
| 66 | + |
| 67 | +代码支持:Python3 |
| 68 | + |
| 69 | +Python3 Code: |
| 70 | + |
| 71 | +```py |
| 72 | +class Solution: |
| 73 | + def solve(self, nums): |
| 74 | + n = len(nums) |
| 75 | + if not n: return 0 |
| 76 | + dp = [[1, 0] for _ in range(n)] |
| 77 | + ans = 1 |
| 78 | + |
| 79 | + for i in range(1,n): |
| 80 | + if nums[i] > nums[i-1]: |
| 81 | + dp[i][0] = dp[i-1][0] + 1 |
| 82 | + dp[i][1] = dp[i-1][1] + 1 |
| 83 | + else: |
| 84 | + dp[i][0] = 1 |
| 85 | + dp[i][1] = 1 |
| 86 | + if i > 1 and nums[i] > nums[i-2]: |
| 87 | + dp[i][1] = max(dp[i][1], 1 + dp[i-2][0]) |
| 88 | + ans = max(ans, dp[i][0], dp[i][1]) |
| 89 | + |
| 90 | + return ans |
| 91 | + |
| 92 | +``` |
| 93 | + |
| 94 | +**复杂度分析** |
| 95 | + |
| 96 | +令 n 为数组长度。 |
| 97 | + |
| 98 | +- 时间复杂度:$O(n)$ |
| 99 | +- 空间复杂度:$O(n)$ |
| 100 | + |
| 101 | +力扣的小伙伴可以[关注我](https://leetcode-cn.com/u/fe-lucifer/),这样就会第一时间收到我的动态啦~ |
| 102 | + |
| 103 | +以上就是本文的全部内容了。大家对此有何看法,欢迎给我留言,我有时间都会一一查看回答。更多算法套路可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 40K star 啦。大家也可以关注我的公众号《力扣加加》带你啃下算法这块硬骨头。 |
0 commit comments