题目链接:https://leetcode.com/problems/house-robber/
简单归纳题目为:给定一组非负整数数组num,从中找值最大的子序列,要求子序列中任意两个元素在原数组中都不相邻。
子序列问题,这个就让我想到了最长公共子序列,所以一开始想到的解决办法也就是采用动态规划来做了。
处理动态规划问题的时候一般要考虑两个问题,一个是d[i]代表什么,另一个则是如何用d[0],d[1],..,d[i-1]来表示d[i]。
一般d[i]的设定都与问题相关,这里我设定d[i]为在数组中下标为0~i的这部分数组上,值最大子序列得到的值。
那么如何根据之前的d[0],d[1],..,d[i-1]来得到d[i]呢?
我喜欢用例子来找规律。
比如1,2,3,d[0] = 1,d[1] =2,当i=2时,因为(1+3 )>2,所以d[2] = d[0] + num[2] = 1+3=4。
比如1,2,3,3,d[0] = 1, d[1] =2,d[2]=4,当i=3时,因为(d[1]+num[3])>d[2],所以d[3] = d[1]+num[3] = 2+3=5。
那么在考虑d[i]的时候,我们的问题便是num[i]是否要加入到子序列中去,如果num[i-1]在子序列中那么num[i]便不能在子序列中,所以:
1.如果d[i-1] == d[i-2] ,那么说明num[i-1]不在子序列,又因为num[i]>=0,所以可以将num[i]直接加入到子序列
2.如果d[i-1] != d[i-2],那么说明num[i-1]在子序列的,那么就要考虑是留num[i-1]还是num[i]在子序列中,所以让d[i-1]与d[i-2]+num[i]直接进行比较来得到结果。
具体代码如下:
class Solution {
public:
int rob(vector<int> &num) {
int size = num.size();
if (size <= 0 )
return 0;
int *rob_money = new int[size];
int i = 0;
for (; i < size; i++)
{
int prev_money1 = ((i-2)>=0)?rob_money[i-2]:0;
int prev_money2 = ((i-1)>=0)?rob_money[i-1]:0;
//rob_money[i-1] doesn't contain num[i-1]
if (prev_money1 == prev_money2)
{
rob_money[i] = prev_money2 + num[i];
}
else
{
if ((prev_money1 + num[i]) > prev_money2)
{
rob_money[i] = prev_money1 + num[i];
}
else
rob_money[i] = prev_money2;
}
}
return rob_money[size - 1];
}
};