学习动态规划|不同路径、最小路径和、打家劫舍、打家劫舍iii
62 不同路径
动态规划,dp[i][j]表示从左上角到(i,j)的路径数量 dp[i][j] = dp[i-1][j] + dp[i][j-1]
import java. util. Arrays ;
public class $62 { public int uniquePaths ( int m, int n) { int [ ] [ ] dp = new int [ m] [ n] ; for ( int i = 0 ; i < m; i++ ) { dp[ i] [ 0 ] = 1 ; } for ( int i = 0 ; i < n; i++ ) { dp[ 0 ] [ i] = 1 ; } for ( int i = 1 ; i < m; i++ ) { for ( int j = 1 ; j < n; j++ ) { dp[ i] [ j] = dp[ i- 1 ] [ j] + dp[ i] [ j- 1 ] ; } } return dp[ m- 1 ] [ n- 1 ] ; } public int uniquePaths2 ( int m, int n) { int [ ] dp = new int [ n] ; Arrays . fill ( dp, 1 ) ; for ( int i = 1 ; i < m; i++ ) { for ( int j = 1 ; j < n; j++ ) { dp[ j] += dp[ j- 1 ] ; } } return dp[ n- 1 ] ; }
}
import java. util. Arrays ;
public class $62 { public int uniquePaths2 ( int m, int n) { int [ ] dp = new int [ n] ; Arrays . fill ( dp, 1 ) ; for ( int i = 1 ; i < m; i++ ) { for ( int j = 1 ; j < n; j++ ) { dp[ j] += dp[ j- 1 ] ; } } return dp[ n- 1 ] ; }
}
64 最小路径和
动态规划,dp[i][j]表示从左上角到(i,j)的最小路径和 grid[i][j] = Math.min(grid[i-1][j], grid[i][j-1]) + grid[i][j]
public class $64 { public int minPathSum ( int [ ] [ ] grid) { for ( int i = 0 ; i < grid. length; i++ ) { for ( int j = 0 ; j < grid[ i] . length; j++ ) { if ( i== 0 && j== 0 ) continue ; else if ( i!= 0 && j== 0 ) grid[ i] [ j] = grid[ i- 1 ] [ j] + grid[ i] [ j] ; else if ( i== 0 && j!= 0 ) grid[ i] [ j] = grid[ i] [ j- 1 ] + grid[ i] [ j] ; else grid[ i] [ j] = Math . min ( grid[ i- 1 ] [ j] , grid[ i] [ j- 1 ] ) + grid[ i] [ j] ; } } return grid[ grid. length- 1 ] [ grid[ 0 ] . length- 1 ] ; }
}
198 打家劫舍
动态规划,nums[i]表示前i间房屋能偷窃到的最高总金额 nums[i] = Math.max(nums[i-1], nums[i-2]+nums[i]);
public class $198 { public int rob ( int [ ] nums) { if ( nums == null || nums. length == 0 ) { return 0 ; } if ( nums. length == 1 ) { return nums[ 0 ] ; } nums[ 1 ] = Math . max ( nums[ 0 ] , nums[ 1 ] ) ; for ( int i = 2 ; i < nums. length; i++ ) { nums[ i] = Math . max ( nums[ i- 1 ] , nums[ i- 2 ] + nums[ i] ) ; } return nums[ nums. length- 1 ] ; }
}
337 打家劫舍iii
树形动态规划 我们可以用 f(o)表示选择 o节点的情况下,o节点的子树上被选择的节点的最大权值和; g(o)表示不选择 o节点的情况下,o节点的子树上被选择的节点的最大权值和; l 和 r代表 o 的左右孩子。 当 o 被选中时:o 的左右孩子都不能被选中, 故 o 被选中情况下子树上被选中点的最大权值和为 l和 r不被选中的最大权值和 + o的值
f(o)=g(l)+g(r)+o.val
当 o不被选中时,o的左右孩子可以被选中,也可以不被选中。 对于 o的某个具体的孩子 x,它对 o 的贡献是 x被选中和不被选中情况下权值和的较大值。
g(o)=max{f(l),g(l)} + max{f(r),g(r)}
import java. util. HashMap ;
import java. util. Map ;
public class $337 { Map < TreeNode , Integer > f = new HashMap < > ( ) ; Map < TreeNode , Integer > g = new HashMap < > ( ) ; public int rob ( TreeNode root) { process ( root) ; return Math . max ( f. getOrDefault ( root, 0 ) , g. getOrDefault ( root, 0 ) ) ; } private void process ( TreeNode root) { if ( root == null ) { return ; } process ( root. left) ; process ( root. right) ; f. put ( root, root. val + g. getOrDefault ( root. left, 0 ) + g. getOrDefault ( root. right, 0 ) ) ; g. put ( root, Math . max ( f. getOrDefault ( root. left, 0 ) , g. getOrDefault ( root. left, 0 ) ) + Math . max ( f. getOrDefault ( root. right, 0 ) , g. getOrDefault ( root. right, 0 ) ) ) ; } public int rob2 ( TreeNode root) { int [ ] rootStatus = process2 ( root) ; return Math . max ( rootStatus[ 0 ] , rootStatus[ 1 ] ) ; } private int [ ] process2 ( TreeNode root) { if ( root == null ) { return new int [ ] { 0 , 0 } ; } int [ ] l = process2 ( root. left) ; int [ ] r = process2 ( root. right) ; int selected = root. val + l[ 1 ] + r[ 1 ] ; int notSelected = Math . max ( l[ 0 ] , l[ 1 ] ) + Math . max ( r[ 0 ] , r[ 1 ] ) ; return new int [ ] { selected, notSelected} ; }
}