打家劫舍问题
题目:你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
示例 2:
输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
偷窃到的最高金额 = 2 + 9 + 1 = 12 。
对于求最优解得题目,我编码效率最快的,自然是递归,但是,递归在数组的长度越来越长是,所需的时间也会飞速增长。因为递归进行了很多重复的运算。而使用动态规划,可以极大得减小重复计算带来的时间的成本。
所以,对于本题而言,或许动态规划更加适合当前题目的情景。根据题目规则我们可以得到几个信息。
Opt[i] = ( Opt[i - 2] + Nums[i] ) 或者 (Opt[i - 1])
i为第i个元素,opt[i]为第i个及其之前的元素的最优解(不考虑之后的元素,只考虑当前元素和之前的元素),Nums为传入的数组
class Solution {
public int rob(int[] nums) {
int y = 0, n = 0;
// 初始化2个变量,代表着选取该节点和不选取该节点。y: yes, n: no
int[] opt = new int[nums.length];
// 初始化一个数组,用于存储每个节点的当前元素及其之前元素的最优解(不管之后的元素 是否选择)
if (nums.length == 0)
{
// 如果传入的数组为空,返回值为0
return 0;
}
if (nums.length == 1)
{
// 如果传入的值为1,返回值为当前数组的唯一元素
return nums[0];
}
// 如果,满足传入数组的长度大于等于2
opt[0] = nums[0];
opt[1] = Math.max(nums[0],nums[1]);
// 第一个元素及之前元素的最优解为第一个元素本身
// 第二个元素及之前元素的最优解为第一个元素或者第二个元素(取大值)
for(int i = 2;i <= nums.length - 1; i++ )
{
// 循环计算,2和2之后每一个元素及之前元素的最优解
// 每个节点都会遇到2个可能,需要当前元素和不需要当前元素
y = nums[i] + opt[i - 2];
n = opt[i - 1];
opt[i] = Math.max(y,n);
// 取最优解
}
Arrays.sort(opt);
// 对最优解进行排序,取最大值即为当前题目的最优解
return opt[nums.length - 1];
// 返回排序后最后一个元素(最大的元素)
}
}