|
| 1 | +# [2355. Maximum Number of Books You Can Take](https://leetcode.cn/problems/maximum-number-of-books-you-can-take) |
| 2 | + |
| 3 | +[English Version](/solution/2300-2399/2355.Maximum%20Number%20of%20Books%20You%20Can%20Take/README_EN.md) |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +<!-- 这里写题目描述 --> |
| 8 | + |
| 9 | +<p>You are given a <strong>0-indexed</strong> integer array <code>books</code> of length <code>n</code> where <code>books[i]</code> denotes the number of books on the <code>i<sup>th</sup></code> shelf of a bookshelf.</p> |
| 10 | + |
| 11 | +<p>You are going to take books from a <strong>contiguous</strong> section of the bookshelf spanning from <code>l</code> to <code>r</code> where <code>0 <= l <= r < n</code>. For each index <code>i</code> in the range <code>l <= i < r</code>, you must take <strong>strictly fewer</strong> books from shelf <code>i</code> than shelf <code>i + 1</code>.</p> |
| 12 | + |
| 13 | +<p>Return <em>the <strong>maximum</strong> number of books you can take from the bookshelf.</em></p> |
| 14 | + |
| 15 | +<p> </p> |
| 16 | +<p><strong>Example 1:</strong></p> |
| 17 | + |
| 18 | +<pre> |
| 19 | +<strong>Input:</strong> books = [8,5,2,7,9] |
| 20 | +<strong>Output:</strong> 19 |
| 21 | +<strong>Explanation:</strong> |
| 22 | +- Take 1 book from shelf 1. |
| 23 | +- Take 2 books from shelf 2. |
| 24 | +- Take 7 books from shelf 3. |
| 25 | +- Take 9 books from shelf 4. |
| 26 | +You have taken 19 books, so return 19. |
| 27 | +It can be proven that 19 is the maximum number of books you can take. |
| 28 | +</pre> |
| 29 | + |
| 30 | +<p><strong>Example 2:</strong></p> |
| 31 | + |
| 32 | +<pre> |
| 33 | +<strong>Input:</strong> books = [7,0,3,4,5] |
| 34 | +<strong>Output:</strong> 12 |
| 35 | +<strong>Explanation:</strong> |
| 36 | +- Take 3 books from shelf 2. |
| 37 | +- Take 4 books from shelf 3. |
| 38 | +- Take 5 books from shelf 4. |
| 39 | +You have taken 12 books so return 12. |
| 40 | +It can be proven that 12 is the maximum number of books you can take. |
| 41 | +</pre> |
| 42 | + |
| 43 | +<p><strong>Example 3:</strong></p> |
| 44 | + |
| 45 | +<pre> |
| 46 | +<strong>Input:</strong> books = [8,2,3,7,3,4,0,1,4,3] |
| 47 | +<strong>Output:</strong> 13 |
| 48 | +<strong>Explanation:</strong> |
| 49 | +- Take 1 book from shelf 0. |
| 50 | +- Take 2 books from shelf 1. |
| 51 | +- Take 3 books from shelf 2. |
| 52 | +- Take 7 books from shelf 3. |
| 53 | +You have taken 13 books so return 13. |
| 54 | +It can be proven that 13 is the maximum number of books you can take. |
| 55 | +</pre> |
| 56 | + |
| 57 | +<p> </p> |
| 58 | +<p><strong>Constraints:</strong></p> |
| 59 | + |
| 60 | +<ul> |
| 61 | + <li><code>1 <= books.length <= 10<sup>5</sup></code></li> |
| 62 | + <li><code>0 <= books[i] <= 10<sup>5</sup></code></li> |
| 63 | +</ul> |
| 64 | + |
| 65 | +## 解法 |
| 66 | + |
| 67 | +<!-- 这里可写通用的实现逻辑 --> |
| 68 | + |
| 69 | +**方法一:单调栈 + 动态规划** |
| 70 | + |
| 71 | +设 $dp[i]$ 表示以 $books[i]$ 结尾时能取走的书的最大数量。 |
| 72 | + |
| 73 | +若从 $i$ 到 $0$ 可以取成一个公差为 $1$ 的等差数列,那么 $dp[i]$ 可以直接通过等差数列求和算出。 |
| 74 | + |
| 75 | +若从 $i$ 到 $0$ 不能取成一个公差为 $-1$ 的等差数列,即这个规律在某个 $j$ 处断掉了($0 \le j \lt i$),那么一定有 $books[j] \lt books[i] - (i-j)$,也即 $books[j] - j \lt books[i] - i$,利用单调栈在新数组 $books[i] - i$ 的每个位置,找到左边第一个比它严格小的数的位置,可以求出符合题意的 $j$,此时 $dp[i]=dp[j] + \sum_{k=j+1}^{i} (books[k]-k)$。 |
| 76 | + |
| 77 | +答案为 $max(dp[i])$。 |
| 78 | + |
| 79 | +时间复杂度 $O(n)$。 |
| 80 | + |
| 81 | +<!-- tabs:start --> |
| 82 | + |
| 83 | +### **Python3** |
| 84 | + |
| 85 | +<!-- 这里可写当前语言的特殊实现逻辑 --> |
| 86 | + |
| 87 | +```python |
| 88 | +class Solution: |
| 89 | + def maximumBooks(self, books: List[int]) -> int: |
| 90 | + nums = [v - i for i, v in enumerate(books)] |
| 91 | + n = len(nums) |
| 92 | + left = [-1] * n |
| 93 | + stk = [] |
| 94 | + for i, v in enumerate(nums): |
| 95 | + while stk and nums[stk[-1]] >= v: |
| 96 | + stk.pop() |
| 97 | + if stk: |
| 98 | + left[i] = stk[-1] |
| 99 | + stk.append(i) |
| 100 | + ans = 0 |
| 101 | + dp = [0] * n |
| 102 | + dp[0] = books[0] |
| 103 | + for i, v in enumerate(books): |
| 104 | + j = left[i] |
| 105 | + cnt = min(v, i - j) |
| 106 | + u = v - cnt + 1 |
| 107 | + s = (u + v) * cnt // 2 |
| 108 | + dp[i] = s + (0 if j == -1 else dp[j]) |
| 109 | + ans = max(ans, dp[i]) |
| 110 | + return ans |
| 111 | +``` |
| 112 | + |
| 113 | +### **Java** |
| 114 | + |
| 115 | +<!-- 这里可写当前语言的特殊实现逻辑 --> |
| 116 | + |
| 117 | +```java |
| 118 | +class Solution { |
| 119 | + public long maximumBooks(int[] books) { |
| 120 | + int n = books.length; |
| 121 | + int[] nums = new int[n]; |
| 122 | + for (int i = 0; i < n; ++i) { |
| 123 | + nums[i] = books[i] - i; |
| 124 | + } |
| 125 | + int[] left = new int[n]; |
| 126 | + Arrays.fill(left, -1); |
| 127 | + Deque<Integer> stk = new ArrayDeque<>(); |
| 128 | + for (int i = 0; i < n; ++i) { |
| 129 | + while (!stk.isEmpty() && nums[stk.peek()] >= nums[i]) { |
| 130 | + stk.pop(); |
| 131 | + } |
| 132 | + if (!stk.isEmpty()) { |
| 133 | + left[i] = stk.peek(); |
| 134 | + } |
| 135 | + stk.push(i); |
| 136 | + } |
| 137 | + long ans = 0; |
| 138 | + long[] dp = new long[n]; |
| 139 | + dp[0] = books[0]; |
| 140 | + for (int i = 0; i < n; ++i) { |
| 141 | + int j = left[i]; |
| 142 | + int v = books[i]; |
| 143 | + int cnt = Math.min(v, i - j); |
| 144 | + int u = v - cnt + 1; |
| 145 | + long s = (long) (u + v) * cnt / 2; |
| 146 | + dp[i] = s + (j == -1 ? 0 : dp[j]); |
| 147 | + ans = Math.max(ans, dp[i]); |
| 148 | + } |
| 149 | + return ans; |
| 150 | + } |
| 151 | +} |
| 152 | +``` |
| 153 | + |
| 154 | +### **C++** |
| 155 | + |
| 156 | +```cpp |
| 157 | +using ll = long long; |
| 158 | + |
| 159 | +class Solution { |
| 160 | +public: |
| 161 | + long long maximumBooks(vector<int>& books) { |
| 162 | + int n = books.size(); |
| 163 | + vector<int> nums(n); |
| 164 | + for (int i = 0; i < n; ++i) nums[i] = books[i] - i; |
| 165 | + vector<int> left(n, -1); |
| 166 | + stack<int> stk; |
| 167 | + for (int i = 0; i < n; ++i) |
| 168 | + { |
| 169 | + while (!stk.empty() && nums[stk.top()] >= nums[i]) stk.pop(); |
| 170 | + if (!stk.empty()) left[i] = stk.top(); |
| 171 | + stk.push(i); |
| 172 | + } |
| 173 | + vector<ll> dp(n); |
| 174 | + dp[0] = books[0]; |
| 175 | + ll ans = 0; |
| 176 | + for (int i = 0; i < n; ++i) |
| 177 | + { |
| 178 | + int v = books[i]; |
| 179 | + int j = left[i]; |
| 180 | + int cnt = min(v, i - j); |
| 181 | + int u = v - cnt + 1; |
| 182 | + ll s = 1ll * (u + v) * cnt / 2; |
| 183 | + dp[i] = s + (j == -1 ? 0 : dp[j]); |
| 184 | + ans = max(ans, dp[i]); |
| 185 | + } |
| 186 | + return ans; |
| 187 | + } |
| 188 | +}; |
| 189 | +``` |
| 190 | +
|
| 191 | +### **Go** |
| 192 | +
|
| 193 | +```go |
| 194 | +func maximumBooks(books []int) int64 { |
| 195 | + n := len(books) |
| 196 | + nums := make([]int, n) |
| 197 | + left := make([]int, n) |
| 198 | + for i, v := range books { |
| 199 | + nums[i] = v - i |
| 200 | + left[i] = -1 |
| 201 | + } |
| 202 | + stk := []int{} |
| 203 | + for i, v := range nums { |
| 204 | + for len(stk) > 0 && nums[stk[len(stk)-1]] >= v { |
| 205 | + stk = stk[:len(stk)-1] |
| 206 | + } |
| 207 | + if len(stk) > 0 { |
| 208 | + left[i] = stk[len(stk)-1] |
| 209 | + } |
| 210 | + stk = append(stk, i) |
| 211 | + } |
| 212 | + dp := make([]int, n) |
| 213 | + dp[0] = books[0] |
| 214 | + ans := 0 |
| 215 | + for i, v := range books { |
| 216 | + j := left[i] |
| 217 | + cnt := min(v, i-j) |
| 218 | + u := v - cnt + 1 |
| 219 | + s := (u + v) * cnt / 2 |
| 220 | + dp[i] = s |
| 221 | + if j != -1 { |
| 222 | + dp[i] += dp[j] |
| 223 | + } |
| 224 | + ans = max(ans, dp[i]) |
| 225 | + } |
| 226 | + return int64(ans) |
| 227 | +} |
| 228 | +
|
| 229 | +func max(a, b int) int { |
| 230 | + if a > b { |
| 231 | + return a |
| 232 | + } |
| 233 | + return b |
| 234 | +} |
| 235 | +
|
| 236 | +func min(a, b int) int { |
| 237 | + if a < b { |
| 238 | + return a |
| 239 | + } |
| 240 | + return b |
| 241 | +} |
| 242 | +``` |
| 243 | + |
| 244 | +### **TypeScript** |
| 245 | + |
| 246 | +```ts |
| 247 | + |
| 248 | +``` |
| 249 | + |
| 250 | +### **...** |
| 251 | + |
| 252 | +``` |
| 253 | +
|
| 254 | +``` |
| 255 | + |
| 256 | +<!-- tabs:end --> |
0 commit comments