挑战dp----打家劫舍II(动态规划)

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

示例 1:

输入: [2,3,2]
输出: 3
解释: 你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

示例 2:

输入: [1,2,3,1]
输出: 4
解释: 你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

题目链接(leetcode)

思路:这是leetcode第一个打家劫舍版本的升级版,因为围成了一个圈,所以要考虑头和尾。
先看不顾头尾的做法:定义数组dp,dp[i]表示前i家可偷取的最高金额。对于第i家,小偷有两种选择,如果不偷第i家,则最高金额为前一家,即dp[i]=dp[i–1],如果要偷第i家,则最高金额为第i家的金额加上第i-2家的最高金额,即dp[i]=dp[i-2]+nums[i],取最大值。

由于头尾两家不能同时偷取,所以要dp两次,一次是不偷第一家,一次是偷第一家不偷最后一家,取最大值。

参考代码:

class Solution {
    
    public int rob(int[] nums) 
	{
		if(nums.length==0)
			return 0;
		else if(nums.length==1)
			return nums[0];
		else if(nums.length==2)
			return Math.max(nums[0], nums[1]);
		int[] dp1=new int[nums.length];
		dp1[0]=0;
		dp1[1]=nums[1];
		for(int i=2;i<dp1.length;i++)
			dp1[i]=Math.max(dp1[i-1], dp1[i-2]+nums[i]);
		
		int[] dp2=new int[nums.length];
		dp2[0]=nums[0];
		dp2[1]=Math.max(nums[1],dp2[0]);
		for(int i=2;i<dp2.length-1;i++)
			dp2[i]=Math.max(dp2[i-1], dp2[i-2]+nums[i]);
		dp2[dp2.length-1]=dp2[dp2.length-2];
		return Math.max(dp1[nums.length-1], dp2[nums.length-1]);
    }

}
发布了72 篇原创文章 · 获赞 18 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41022094/article/details/103365173