House Robber I - 由数组中不相邻元素组成的子数组,使其和最大

题目来源:http://www.lintcode.com/zh-cn/problem/house-robber/

题目描述

假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,在不触动报警装置的情况下, 你最多可以得到多少钱。

翻译(转化)

在数组中取出一个或多个不相邻数,使其和最大,即找到max(不相邻元素组成的子数组)

解决方法 = 动态规划

举例,求a = [1,8,5,6,9]中不相邻元素组成的子数组的最大和

a[0~index]max(不相邻元素组成的子数组)
a[0]m0 = 1
a[0~1] = a[0,1]m1 = max(m0 , a[1]) = 8
a[0~2] = a[0,1,2]m2 = max( m0 + a[2] , m1) = max(1 + 5, 8) = 8
a[0~3] = a[0,1,2,3]m3 = max( m0 + a[3] , m1 + a[3] , m2) = max(m1 + a[3] , m2) = max(14,8) = 14
a[0~4] = a[0,1,2,3,4]m4 = max( m0 + a[4] , m1 + a[4] , m2 + a[4] , m3) = max(m2 + a[4] , m3) = max(8 + 9 ,14) = 17

疑问1,m3 = max( m0 + a[3] , m1 + a[3] , m2) ,为什么只有m2不需要加上a[3]?

m2对应的数组是a[0~2],

  1. 假设a[0~2]的最大不相邻子数组a2用到了最后一个元素,那么a[0~3]的最大不相邻的子数组肯定不是a2+a[3];
  2. 假设a[0~2]的最大不相邻子数组a2没有用到最后一个元素,那么a[0~2]等于a[0~1]的最大不相邻子数组;

所以m2不需要加a[3]。

同理可得:a[0~n] = max(a[0] + a[n] , a[0~1] + a[n] ….a[0~n-2] + a[n] , a[0~n - 1])

疑问2,以上等式转换是怎么来的?

a[0~3] = max( m0 + a[3] , m1 + a[3] , m2)
因为m1 = max(m0, a[1]);
所以m1 + a[3] >= m0 + a[3];
所以a[0~3] = max(m1 + a[3] , m2) = max(8 + 6, 8) = 14;

a[0~4] = max( m0 + a[4] , m1 + a[4] , m2 + a[4] , m3);
因为m1 = max(m0, a[1]),m2 = max( m0 + a[2] , m1);
所以m2 >= m1 >= m0;
所以a[0~4] = max(m2 + a[4] , m3);

由以上可以得出状态转移方程:dp[n] = max(dp[n - 2] + a[n] , dp[n - 1])

代码

long long houseRobber(vector<int> nums) {
  int size = nums.size();
  if (size == 0) {
    return 0;
  }
  if (size == 1) {
    return nums[0];
  }
  if (size == 2) {
    return nums[0] > nums[1] ? nums[0]:nums[1];
  }
  long long n1 = nums[0];
  long long n2 = n1 > nums[1]?n1:nums[1];
  long long n3, n4;
  for (int i = 2; i < size; i++) {
    n3 = n1 + nums[i];
    n4 = n3 > n2 ? n3:n2;
    n1 = n2;
    n2 = n4;
  }
  return n1 > n2 ? n1:n2;
}

请尊重作者的劳动,转载请注明作者及原文地址(http://blog.csdn.net/lis_12/article/details/55187884).

如果觉得本文对您有帮助,请点击‘顶’支持一下,您的支持是我写作最大的动力,谢谢。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值