@@ -283,97 +283,60 @@ bool canJump(vector<int>& nums) {
283283> 数组中的每个元素代表你在该位置可以跳跃的最大长度。
284284> 你的目标是使用最少的跳跃次数到达数组的最后一个位置。
285285
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;
327295 }
328- f[i]=f[idx]+1
296+ // 假设你总是可以到达数组的最后一个位置。
297+ // 可以认定farest + nums[ farest] 一定会大于i
298+ cache[ i] = cache[ farest] + 1;
329299 }
330- return f[n- 1 ]
300+ return cache.back();
331301}
332-
333302```
334303
335304### [palindrome-partitioning-ii](https://leetcode-cn.com/problems/palindrome-partitioning-ii/)
336305
337306> 给定一个字符串 _s_,将 _s_ 分割成一些子串,使每个子串都是回文串。
338307> 返回符合要求的最少分割次数。
339308
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();
377340}
378341```
379342
0 commit comments