leetcode-DP
一、模板
递归(自上而下)
递归 -> 记忆化搜索 (自上而下)
记忆化搜索 -> DP (自下而上)
1 2 3 4 5 6 7 8 9 for (let i = 0 ;i<n;i++) dp[0 ][i] = 1 for (let i = 0 ;i<m;i++) dp[i][0 ] = 1 for (let i = 1 ;i<m;i++) for (let j = 1 ;j<n;j++) dp[i][j] = dp[i-1 ][j] + dp[i][j-1 ]
二、题目
F(0) = 1, F(1) = 1, F(n) = F(n-1) + F(n-2)
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 function fib (n ) { if (n === 0 ) return 0 if (n === 1 ) return 1 return fib(n-1 ) + fib(n-2 ) } const memo = new Array (n + 1 ).fill(-1 )function fib (n ) { if (n === 0 ) return 0 if (n === 1 ) return 1 if (memo[n] === -1 ) memo[n] = fib(n - 1 ) + fib(n - 2 ) return memo[n] } function fib (n ) { let memo = new Array (n + 1 ).fill(-1 ) memo[0 ] = 0 memo[1 ] = 1 for (let i = 2 ; i <= n; i++) { memo[i] = memo[i - 1 ] + memo[i - 2 ] } return memo[n] }
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 var climbStairs = function (n ) { return _climb(n) function _climb (n ) { if (n === 0 || n === 1 ) return 1 return climbStairs(n - 1 ) + climbStairs(n - 2 ) } } var climbStairs = function (n ) { let memo = new Array (n + 1 ).fill(0 ) memo[0 ] = 1 memo[1 ] = 1 memo[2 ] = 2 for (let i = 3 ; i <= n; i++) memo[i] = memo[i - 1 ] + memo[i - 2 ] + memo[i - 3 ] return memo[n] } var climbStairs = function (n ) { const memo = new Array (n + 1 ).fill(-1 ) return _climb(n) function _climb (n ) { if (n === 0 || n === 1 ) return 1 if (memo[n] === -1 ) memo[n] = _climb(n - 2 ) + _climb(n - 1 ) return memo[n] } }; var climbStairs = function (n ) { const memo = new Array (n + 1 ).fill(-1 ) memo[0 ] = 1 memo[1 ] = 1 for (let i = 2 ;i<=n;i++) memo[i] = memo[i-1 ] + memo[i-2 ] return memo[n] };
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 60 61 62 63 64 65 66 67 68 var minimumTotal = function (triangle ) { return _minimumTotal(triangle,0 ,0 ) function _minimumTotal (triangle,depth,index ) { if (depth === triangle.length) return 0 return triangle[depth][index] + Math .min(_minimumTotal(triangle,depth+1 ,index),_minimumTotal(triangle,depth+1 ,index+1 )) } }; var minimumTotal = function (triangle ) { let memo = new Array (triangle.length) for (let i = 0 ;i<memo.length;i++) memo[i] = new Array (triangle[i].length).fill(0 ) return _minimumTotal(triangle,0 ,0 ) function _minimumTotal (triangle,depth,index ) { if (depth === triangle.length) return 0 if (memo[depth][index] === 0 ) memo[depth][index] = triangle[depth][index] + Math .min(_minimumTotal(triangle,depth+1 ,index),_minimumTotal(triangle,depth+1 ,index+1 )) return memo[depth][index] } }; var minimumTotal = function (triangle ) { let n = triangle.length; let memo = new Array (n+1 ); for (let i = 0 ;i< memo.length;i++) memo[i] = new Array (n+1 ).fill(0 ) for (let i = n - 1 ; i >= 0 ; i--) { for (let j = 0 ; j <= i; j++) { memo[i][j] = Math .min(memo[i + 1 ][j], memo[i + 1 ][j + 1 ]) + triangle[i][j]; } } return memo[0 ][0 ]; }; var minimumTotal = function (triangle ) { let n = triangle.length; let memo = new Array (n+1 ).fill(0 ); for (let i = n - 1 ; i >= 0 ; i--) { for (let j = 0 ; j <= i; j++) { memo[j] = Math .min(memo[j], memo[j + 1 ]) + triangle[i][j]; } } return memo[0 ]; };
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 60 61 62 63 64 65 66 67 68 69 70 var minPathSum = function (grid ) { return dfs(grid, 0 , 0 ) function dfs (grid, depth, index ) { if (depth === grid.length || index === grid[0 ].length) return 0 let min if (depth + 1 >= grid.length) min = dfs(grid, depth, index + 1 ) else if (index + 1 >= grid[0 ].length) min = dfs(grid, depth + 1 , index) else min = Math .min(dfs(grid, depth, index + 1 ), dfs(grid, depth + 1 , index)) return grid[depth][index] + min } } var minPathSum = function (grid ) { let n = grid.length let memo = new Array (n) for (let i = 0 ; i < memo.length; i++) memo[i] = new Array (grid[0 ].length).fill(0 ) return dfs(grid, 0 , 0 ) function dfs (grid, depth, index ) { if (depth === grid.length || index === grid[0 ].length) return 0 let min if (depth + 1 >= grid.length) min = dfs(grid, depth, index + 1 ) else if (index + 1 >= grid[0 ].length) min = dfs(grid, depth + 1 , index) else min = Math .min(dfs(grid, depth, index + 1 ), dfs(grid, depth + 1 , index)) if (memo[depth][index] === 0 ) memo[depth][index] = grid[depth][index] + min return memo[depth][index] } } var minPathSum = function (grid ) { let width = grid[0 ].length,height = grid.length for (let i = 1 ;i<width;i++) grid[0 ][i] += grid[0 ][i-1 ] for (let i = 1 ;i<height;i++) grid[i][0 ] += grid[i-1 ][0 ] for (let i = 1 ;i<height;i++) for (let j = 1 ;j<width;j++) grid[i][j] += Math .min(grid[i-1 ][j],grid[i][j-1 ]) return grid[height-1 ][width-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 var integerBreak = function (n ) { return dfs(n) function dfs (n ) { if (n === 1 ) return 1 let res = -1 for (let i = 1 ; i < n; i++) res = Math .max(res, i * (n - i), i * dfs(n - i)) return res } }; var integerBreak = function (n ) { const memo = new Array (n + 1 ).fill(-1 ) return dfs(n) function dfs (n ) { if (n === 1 ) return 1 if (memo[n] !== -1 ) return memo[n] let res = -1 for (let i = 1 ; i < n; i++) res = Math .max(res, i * (n - i), i * dfs(n - i)) memo[n] = res return res } }; var integerBreak = function (n ) { const memo = new Array (n + 1 ).fill(-1 ) memo[1 ] = 1 for (let i = 2 ;i<=n;i++) for (let j = 1 ;j < i;j++) memo[i] = Math .max(memo[i], j * (i-j), j * memo[i-j]) return memo[n] };
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 var numSquares = function (n ) { return dfs(n) function dfs (n ) { if (n === 0 ) return 0 let count = Number .MAX_SAFE_INTEGER for (let i = 1 ;i*i <= n;i++) count = Math .min(count,dfs(n-i*i)+1 ) return count } }; var numSquares = function (n ) { const memo = new Array (n+1 ).fill(-1 ) return dfs(n) function dfs (n ) { if (n === 0 ) return 0 if (memo[n] !== -1 ) return memo[n] let count = Number .MAX_SAFE_INTEGER for (let i = 1 ;i*i <= n;i++) count = Math .min(count,dfs(n-i*i)+1 ) memo[n] = count return memo[n] } }; var numSquares = function (n ) { const memo = new Array (n + 1 ).fill(0 ) memo[0 ] = 0 for (let i = 1 ; i <= n; i++) { memo[i] = i for (let j = 1 ; i - j * j >= 0 ; j++) memo[i] = Math .min(memo[i], memo[i - j * j] + 1 ) } return memo[n] }
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 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 var numDecodings = function (s ) { return dfs(s) function dfs (s ) { if (s === "" ) return 1 let count = 0 if (s[0 ] !== '0' ) count += dfs(s.slice(1 )) if (s.length >= 2 && s[0 ] === '1' || (s[0 ] === '2' && s[1 ] >= 0 && s[1 ] <= 6 )) { count += dfs(s.slice(2 )) } return count } } var numDecodings = function (s ) { let memo = {} return dfs(s) function dfs (s ) { if (s === "" ) return 1 if (memo[s]) return memo[s] let count = 0 if (s[0 ] !== '0' ) count += dfs(s.slice(1 )) if (s.length >= 2 && s[0 ] === '1' || (s[0 ] === '2' && s[1 ] >= 0 && s[1 ] <= 6 )) { count += dfs(s.slice(2 )) } memo[s] = count return memo[s] } } var numDecodings = function (s ) { let memo = {} return dfs(0 ) function dfs (i ) { if (i === s.length) return 1 if (memo[i]) return memo[i] let count = 0 if (s[i] !== '0' ) count += dfs(i+1 ) if (i < s.length-1 && s[i] === '1' || (s[i] === '2' && s[i+1 ] >= 0 && s[i+1 ] <= 6 )) { count += dfs(i+2 ) } memo[i] = count return memo[i] } } var numDecodings = function (s ) { if (s.length === 0 ) return 0 let memo = new Array (s.length+1 ).fill(0 ) memo[0 ] = 1 memo[1 ] = s[0 ] === '0' ? 0 : 1 for (let i = 2 ;i<=s.length;i++){ if (s[i-1 ] !== "0" ) memo[i] += memo[i-1 ] if (s[i-2 ] === '1' || (s[i-2 ] === "2" && s[i-1 ] >=0 && s[i-1 ] <=6 )) memo[i] += memo[i-2 ] } return memo[s.length] }
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 var uniquePaths = function (m, n ) { return dfs(0 ,0 ,m,n) function dfs (i,j,m,n ) { if (i > m-1 || j > n-1 ) return 0 if (i === m-1 && j === n-1 ) return 1 return dfs(i+1 ,j,m,n) + dfs(i,j+1 ,m,n) } }; var uniquePaths = function (m, n ) { let memo = new Array (m).fill(0 ).map(()=> new Array (n).fill(0 )) return dfs(0 ,0 ,m,n) function dfs (i,j,m,n ) { if (i > m-1 || j > n-1 ) return 0 if (i === m-1 && j === n-1 ) return 1 if (memo[i][j] === 0 ) memo[i][j] = dfs(i+1 ,j,m,n) + dfs(i,j+1 ,m,n) return memo[i][j] } }; var uniquePaths = function (m, n ) { const dp = new Array (m).fill(0 ).map(()=> new Array (n).fill(0 )) for (let i = 0 ;i<n;i++) dp[0 ][i] = 1 for (let i = 0 ;i<m;i++) dp[i][0 ] = 1 for (let i = 1 ;i<m;i++) for (let j = 1 ;j<n;j++) dp[i][j] = dp[i-1 ][j] + dp[i][j-1 ] return dp[m-1 ][n-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 60 61 var uniquePathsWithObstacles = function (obstacleGrid ) { let height = obstacleGrid.length, width = obstacleGrid[0 ].length return dp(0 , 0 , obstacleGrid) function dp (i, j, obstacleGrid ) { if (i > height - 1 || j > width - 1 || obstacleGrid[i][j] === 1 ) return 0 if (i === height - 1 && j === width - 1 ) return 1 return dp(i + 1 , j, obstacleGrid) + dp(i, j + 1 , obstacleGrid) } } var uniquePathsWithObstacles = function (obstacleGrid ) { let height = obstacleGrid.length, width = obstacleGrid[0 ].length let memo = new Array (height).fill(0 ).map(() => new Array (width).fill(0 )) return dp(0 , 0 , obstacleGrid) function dp (i, j, obstacleGrid ) { if (i > height - 1 || j > width - 1 || obstacleGrid[i][j] === 1 ) return 0 if (i === (height - 1 ) && j === (width - 1 )) return 1 if (memo[i][j]) return memo[i][j] memo[i][j] = dp(i + 1 , j, obstacleGrid) + dp(i, j + 1 , obstacleGrid) return memo[i][j] } }; var uniquePathsWithObstacles = function (obstacleGrid ) { let height = obstacleGrid.length, width = obstacleGrid[0 ].length let memo = new Array (height).fill(0 ).map(() => new Array (width).fill(0 )) for (let i = 0 ; i<height && obstacleGrid[i][0 ] === 0 ;i++) memo[i][0 ] = 1 for (let i = 0 ; i<width && obstacleGrid[0 ][i] === 0 ;i++) memo[0 ][i] = 1 for (let i = 1 ;i<height;i++) for (let j = 1 ;j<width;j++) if (obstacleGrid[i][j] === 0 ) memo[i][j] = memo[i-1 ][j] + memo[i][j-1 ] return memo[height-1 ][width-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 var longestCommonSubsequence = function (text1, text2 ) { let memo = new Array (text1.length).fill(0 ).map(() => new Array (text2.length).fill(0 )) return dfs(text1.length - 1 , text2.length - 1 ) function dfs (i, j ) { if (i === -1 || j === -1 ) return 0 if (memo[i][j]) return memo[i][j] if (text1[i] === text2[j]) memo[i][j] = 1 + dfs(i - 1 , j - 1 ) else memo[i][j] = Math .max( dfs(i - 1 , j), dfs(i, j - 1 ), dfs(i - 1 , j - 1 ) ) return memo[i][j] } }; var longestCommonSubsequence = function (text1, text2 ) { if (!text1.length || !text2.length) return 0 let m = text1.length let n = text2.length let dp = new Array (m+1 ).fill(0 ).map(()=> new Array (n+1 ).fill(0 )) for (let i = 1 ;i<m+1 ;i++) for (let j = 1 ;j<n+1 ;j++){ if (text1[i-1 ] === text2[j-1 ]) dp[i][j] = dp[i-1 ][j-1 ] + 1 else dp[i][j] = Math .max(dp[i-1 ][j],dp[i][j-1 ]) } return dp[m][n] };
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 var rob = function (nums ) { return dfs(nums, 0 ) function dfs (nums, index ) { if (index > nums.length - 1 ) return 0 let res = -1 for (let i = index; i <= nums.length - 1 ; i++) res = Math .max(res, nums[i] + dfs(nums, i + 2 )) return res } }; var rob = function (nums ) { const memo = new Array (nums.length).fill(-1 ) return dfs(nums, 0 ) function dfs (nums, index ) { if (index > nums.length - 1 ) return 0 if (memo[index] !== -1 ) return memo[index] let res = -1 for (let i = index; i <= nums.length - 1 ; i++) res = Math .max(res, nums[i] + dfs(nums, i + 2 )) memo[index] = res return res } }; var rob = function (nums ) { const memo = new Array (nums.length).fill(-1 ) const n = nums.length memo[n - 1 ] = nums[n - 1 ] for (let i = n - 2 ; i >= 0 ; i--) for (let j = i; j < n; j++) memo[i] = Math .max(memo[i], nums[j] + (j + 2 < n ? memo[j + 2 ] : 0 )) return memo[0 ] };
01背包
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 var knapsack01 = (w, v, C ) => { let memo = new Array (w.length).fill(0 ).map(() => new Array (C + 1 ).fill(-1 )) return bestValue(w, v, 1 , C) function bestValue (w, v, index, c ) { if (index >= w.length || c <= 0 ) return 0 if (memo[index][c] !== -1 ) return memo[index][c] let res = bestValue(w, v, index + 1 , c) if (c >= w[index]) res = Math .max(res, v[index] + bestValue(w, v, index + 1 , c - w[index])) memo[index][c] = res return res } } var knapsack01 = (w, v, C ) => { let memo = new Array (w.length).fill(0 ).map(() => new Array (C + 1 ).fill(-1 )) for (let i = 0 ; i < w.length; i++) memo[i][0 ] = 0 for (let i = 0 ; i <= C; i++) memo[0 ][i] = i >= w[0 ] ? v[0 ] : 0 for (let i = 1 ; i < w.length; i++) for (let j = 1 ; j <= C; j++) { memo[i][j] = memo[i - 1 ][j] if (j >= w[i]) memo[i][j] = Math .max(memo[i][j], v[i] + memo[i - 1 ][j - w[i]]) } return memo[w.length - 1 ][C] }