@@ -283,97 +283,60 @@ bool canJump(vector<int>& nums) {
283
283
> 数组中的每个元素代表你在该位置可以跳跃的最大长度。
284
284
> 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
285
285
286
- ``` go
287
- // v1动态规划(其他语言超时参考v2)
288
- func jump (nums []int ) int {
289
- // 状态:f[i] 表示从起点到当前位置最小次数
290
- // 推导:f[i] = f[j],a[j]+j >=i,min(f[j]+1)
291
- // 初始化:f[0] = 0
292
- // 结果:f[n-1]
293
- f := make ([]int , len (nums))
294
- f[0 ] = 0
295
- for i := 1 ; i < len (nums); i++ {
296
- // f[i] 最大值为i
297
- f[i] = i
298
- // 遍历之前结果取一个最小值+1
299
- for j := 0 ; j < i; j++ {
300
- if nums[j]+j >= i {
301
- f[i] = min (f[j]+1 ,f[i])
302
- }
303
- }
304
- }
305
- return f[len (nums)-1 ]
306
- }
307
- func min (a , b int ) int {
308
- if a > b {
309
- return b
310
- }
311
- return a
312
- }
313
- ```
314
-
315
- ``` go
316
- // v2 动态规划+贪心优化
317
- func jump (nums []int ) int {
318
- n := len (nums)
319
- f := make ([]int , n)
320
- f[0 ] = 0
321
- for i := 1 ; i < n; i++ {
322
- // 取第一个能跳到当前位置的点即可
323
- // 因为跳跃次数的结果集是单调递增的,所以贪心思路是正确的
324
- idx := 0
325
- for idx<n&&idx+nums[idx]<i{
326
- idx++
286
+ ``` c++
287
+ int jump (vector<int >& nums) {
288
+ int size = nums.size();
289
+ vector<int > cache(size);
290
+ cache[ 0] = 0;
291
+ // cache[ i + 1] >= cache[ i]
292
+ for (int i = 1, farest = 0; i < size; ++i) {
293
+ while (farest < size && farest + nums[ farest] < i) {
294
+ ++farest;
327
295
}
328
- f[i]=f[idx]+1
296
+ // 假设你总是可以到达数组的最后一个位置。
297
+ // 可以认定farest + nums[ farest] 一定会大于i
298
+ cache[ i] = cache[ farest] + 1;
329
299
}
330
- return f[n- 1 ]
300
+ return cache.back();
331
301
}
332
-
333
302
```
334
303
335
304
### [palindrome-partitioning-ii](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
336
305
337
306
> 给定一个字符串 _s_,将 _s_ 分割成一些子串,使每个子串都是回文串。
338
307
> 返回符合要求的最少分割次数。
339
308
340
- ``` go
341
- func minCut (s string ) int {
342
- // state: f[i] "前i"个字符组成的子字符串需要最少几次cut(个数-1为索引)
343
- // function: f[i] = MIN{f[j]+1}, j < i && [j+1 ~ i]这一段是一个回文串
344
- // intialize: f[i] = i - 1 (f[0] = -1)
345
- // answer: f[s.length()]
346
- if len (s) == 0 || len (s) == 1 {
347
- return 0
348
- }
349
- f := make ([]int , len (s)+1 )
350
- f[0 ] = -1
351
- f[1 ] = 0
352
- for i := 1 ; i <= len (s); i++ {
353
- f[i] = i - 1
354
- for j := 0 ; j < i; j++ {
355
- if isPalindrome (s, j, i-1 ) {
356
- f[i] = min (f[i], f[j]+1 )
357
- }
358
- }
359
- }
360
- return f[len (s)]
361
- }
362
- func min (a , b int ) int {
363
- if a > b {
364
- return b
365
- }
366
- return a
367
- }
368
- func isPalindrome (s string , i , j int ) bool {
369
- for i < j {
370
- if s[i] != s[j] {
371
- return false
372
- }
373
- i++
374
- j--
375
- }
376
- return true
309
+ ```c++
310
+ int minCut(string s) {
311
+ if (s.size() <= 1) {
312
+ return 0;
313
+ }
314
+ auto size = s.size();
315
+ vector<int> cache(size);
316
+ for (int i = 0; i < size; ++i) {
317
+ cache[i] = i;
318
+ }
319
+ vector<vector<bool>> isPalindrome(size, vector<bool>(size));
320
+ for (int right = 0; right < size; ++right) {
321
+ for (int left = 0; left <= right; ++left) {
322
+ // 如果头尾相同,可能为回文!
323
+ // len < 3时,直接判断为回文
324
+ // len >= 3时,判断里面一层,左右往里缩一格
325
+ isPalindrome[left][right] = s[right] == s[left] && (right - left < 3 || isPalindrome[left + 1][right - 1]);
326
+ }
327
+ }
328
+ for (int i = 1; i < size; ++i) {
329
+ if (isPalindrome[0][i]) {
330
+ cache[i] = 0;
331
+ continue;
332
+ }
333
+ for (int j = 0; j < i; ++j) {
334
+ if (isPalindrome[j + 1][i]) {
335
+ cache[i] = min(cache[j] + 1, cache[i]);
336
+ }
337
+ }
338
+ }
339
+ return cache.back();
377
340
}
378
341
```
379
342
0 commit comments