树形dp的入门

题目是leetcode337:打家劫舍3

  

        什么是树形dp呢?就是在树上寻找递推关系,而非是一维数组。有些算法基础的朋友都知道,这种前后互相影响的题目是很适合使用动态规划来解决的,但是如果是在树上,我们该如何使用呢?

       最为关键的是dp数组,每个节点只有两个状态,偷与不偷,我们可以用只有两个元素的一维dp数组来进行记录,而不是所有节点都需要记录,这是与普通dp不同之处。那不记录的话,下层节点的值不就丢失了吗?这也是关键之处,我们应该使用后序遍历来进行遍历,下层节点将状态传递到上层,上层根据下层传入的值进行处理,得到到达本层该节点时的状态,这样到了最上层跟节点,实际上已经考虑到了下层所有节点的状态。加之,对于树来说,根节点是确定的,但是各叶子节点的位置都是不定的,所以应该从叶子向根自下而上递归。

       对于本题,具体而言就是如果偷当前节点,那左右必须取不偷,如果不偷当前节点,则可偷但不一定偷左右节点,这是我们应该取偷与不偷的最大值!这就是具体在每层进行递推的逻辑。

       代码如下:

func rob(root *TreeNode) int {
	dp := treeDP(root)
	return int(math.Max(float64(dp[0]), float64(dp[1])))
}

// 不偷,偷
func treeDP(root *TreeNode) []int {
	if root == nil {
		return []int{0, 0}
	}

	// 一定后序遍历,先得到左右子节点的具体情况,再在该层节点进行递推
	leftDP := treeDP(root.Left)
	rightDP := treeDP(root.Right)

	// 偷当前节点,不偷左右
	dp := make([]int, 2)
	dp[1] = leftDP[0] + rightDP[0] + root.Val

	// 不偷当前节点,可偷左右,注意是可偷,还需要比较下偷与不偷找个最大值
	dp[0] = int(math.Max(float64(leftDP[0]), float64(leftDP[1]))) + int(math.Max(float64(rightDP[0]), float64(rightDP[1])))

	return dp
}

          总之,这是一道非常不错的树形dp入门题目。大家有什么看法呢,欢迎大家来多多交流!        

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值