HouseRob I
问题描述:一个强盗要抢劫一个房屋,但是他不能抢连续的两个房间,比如说ABC房间,他只能抢A和C或者是B,否则就会触发警报,将其抓住。我们知道每个房间都有money,并且money>=0的。 这个题我们可以看作动态规划来解决。
划分子问题 dp[i]表示的是从第1个房间到第i个房间,所能抢到的最大金额。根据子问题求解父问题 dp[i] = max(dp[i-2] + nums[i], dp[i-1])。从第0个到第i个的最大值等于(1)第0个到第i-1个最大值或者(2)0~i-2+nums[i] (因为money一定是正的所以可以直接加)。 最大值就等于这两个里面较大的一个。
代码:
int rob ( vector< int > & nums) {
int size = ( int ) nums. size ( ) ;
if ( size == 0 )
return 0 ;
int dp[ size] ;
memset ( dp, 0 , sizeof ( dp) ) ;
dp[ 0 ] = nums[ 0 ] ;
int res = dp[ 0 ] ;
for ( int i= 1 ; i< size; i++ ) {
if ( ( i- 2 ) >= 0 ) {
dp[ i] = max ( dp[ i- 2 ] + nums[ i] , dp[ i- 1 ] ) ;
} else {
dp[ i] = max ( nums[ i] , dp[ i- 1 ] ) ;
}
res = max ( res, dp[ i] ) ;
}
return res;
}
HouseRob II
问题描述:基本和HouseRobI一致,不同之处在于HouseRob II里面收尾也是相连的。也就是说不能同时取第一个和最后一个房间。 分析,假设我们的数组是从[0~N]. 因为我们不能同时取第一个和最后一个。所以我们可以计算[0~N-1]的最大值Res1和[1 ~ N]的最大值Res2。这样我们就不可能同时取到第一个和最后一个。 现在有一个问题,即如何确保上述的两个最大值里面较大的一个就是我们最终的结果。
假设结果不包含在上述两个里面,因为结果不同时包括第一个和最后一个。 如果说最终的结果包含第一个元素不包含最后一个元素。则这样的解一定是Res1。 如果最终的结果包含最后一个不包括第一个元素,则这样的解一定是Res2。 如果最终的结果既不包含第一个也不包含第二个,则这样的解一定是Res1=Res2。 综上,可以得到Res1和Res2里面的较大值一定是我们最后的结果。
代码:
int rob ( const vector< int > & nums, int l, int r) {
int size = r - l + 1 ;
int dp[ size] ;
memset ( dp, 0 , sizeof ( dp) ) ;
dp[ 0 ] = nums[ l] ;
int res = dp[ 0 ] ;
for ( int i= l+ 1 ; i<= r; i++ ) {
if ( ( i- 2 ) >= l) {
dp[ i- l] = max ( dp[ i- l- 2 ] + nums[ i] , dp[ i- l- 1 ] ) ;
} else {
dp[ i- l] = max ( nums[ i] , dp[ i- l- 1 ] ) ;
}
res = max ( res, dp[ i- l] ) ;
}
return res;
}
int rob ( vector< int > & nums) {
int size = ( int ) nums. size ( ) ;
return max ( rob ( nums, 0 , size- 2 ) , rob ( nums, 1 , size- 1 ) ) ;
}
HouseRob III
问题描述:和HouseRob一样,不同之处在于本题中房屋不是线性排列,而是呈现一个二叉树状的排列。同样抢了某个房子就不能抢与其相邻的房子(父节点和孩子节点)。 分析:
划分成子问题 ,假设说我们的根节点是R,我们将其拆分计算子节点的最大值。子问题的解构建父问题的解 ,假设说我们知道了子节点的最大值,那么我们计算父节点的最大值呢?
因为不能同时取相邻的两个节点 所以最大值={父节点的值+左子树中不包括左孩子的最大值+右子树中不包括右孩子的最大值,左子树的最大值+右子树的最大值}中的最大值 有人可能会有疑问,那如果左子树中的最大值本来就不包括左孩子呢?那这种情况本身就应该在第一种解中。
上面我们说明了,我们不仅要算每个节点的最大值,还需要计算不包括当前节点的最大值。
伪代码:
输入:根节点R 输出:最大值Res1和不包括R的最大值Res2.注意Res1可能等于Res2 如果R等于NULL,则返回0, 0 计算左子树的Res1leftRes1_{left} R e s 1 l e f t 和Res2leftRes2_{left} R e s 2 l e f t 计算右子树的Res1rightRes1_{right} R e s 1 r i g h t 和Res2rightRes2_{right} R e s 2 r i g h t 下面开始计算本节点的Res1Res1 R e s 1 和Res2Res2 R e s 2
Res1=max(R.val+Res2left+Res2right,Res1left+Res1right)Res1 = max(R.val + Res2_{left} + Res2_{right}, Res1_{left} + Res1_{right}) R e s 1 = m a x ( R . v a l + R e s 2 l e f t + R e s 2 r i g h t , R e s 1 l e f t + R e s 1 r i g h t ) Res2=Res1left+Res1rightRes2 = Res1_{left} + Res1_{right} R e s 2 = R e s 1 l e f t + R e s 1 r i g h t
返回Res1和Res2
代码:
class Result{
public:
int low_level;
int high_level;
Result ( ) {
low_level = 0 ;
high_level = 0 ;
}
} ;
Result robBase ( TreeNode* root) {
if ( root == NULL )
{
return Result ( ) ;
}
Result left = robBase ( root-> left) ;
Result right = robBase ( root-> right) ;
int max_value = max ( root-> val + left. low_level + right. low_level, left. high_level + right. high_level) ;
Result res;
res. high_level = max_value;
res. low_level = left. high_level + right. high_level;
return res;
}
int rob ( TreeNode* root) {
if ( root == NULL )
return 0 ;
Result res = robBase ( root) ;
return res. high_level;
}
class Solution ( object ) :
def robBase ( self, root) :
if root is None :
return 0 , 0
l1, l2 = self. robBase( root. left)
r1, r2 = self. robBase( root. right)
res = max ( [ l1 + r1, root. val + l2 + r2] )
return res, l1 + r1
def rob ( self, root) :
"""
:type root: TreeNode
:rtype: int
"""
l1, l2 = self. robBase( root)
return max ( [ l1, l2] )