题目:House Robber
给定一个数组求最大和,要求求和的每个元素不能相邻。
思路:
不要想太复杂,每次记录当前的最大值和前一个位置的最大值,然后比较即可。
具体就是动态规划的思想:
F(i)表示数组前i项中符合上面要求的最大和;choose(i) = true表示F(i)的和中第i项被选中了。
F(i) = max{choose(i - 1) & max{F(i - 1), F(i - 2) + Ai},!choose(i - 1) & F(i - 1) + Ai}
因为!choose(i - 1) & F(i - 1) == F(i - 2);
= max{F(i - 2) + Ai,F(i - 1)}
动态规划:F(i) = max{F(i - 2) + Ai,F(i - 1)}
int LeetCode::rob(vector<int>& nums){ if (!nums.size())return 0; if (nums.size() == 1)return nums.at(0); if (nums.size() == 2)return max(nums.at(0), nums.at(1)); int max = 0;//max找[0,n-1]的最大值1]的最大值 int pre = 0, cur = 0; for (size_t i = 0; i < nums.size(); ++i){ max = max(pre + nums.at(i), cur);//求max pre = cur; cur = max; } return max; }
题目:House RobberII
给定数组是循环的情况,即:首尾相邻。
思路:
和上面类似,只是注意不要考虑最优解是否包含第一个元素,可能也能解决,但是很复杂;
直接分别除去第一个元素或最后一个元素,用上面的方法求出最大值,在取最大就可以了。
int LeetCode::rob2(vector<int>& nums){ if (!nums.size())return 0; if (nums.size() == 1)return nums.at(0); int max1 = 0, max2;//max1找[0,n-2]的最大值,max2找[1,n-1]的最大值 int pre1 = 0,cur1 = 0,pre2 = 0, cur2 = 0; for (size_t i = 0,j = 1; i < nums.size() - 1 && j < nums.size(); ++i,++j){ max1 = max(pre1 + nums.at(i), cur1);//求max1 pre1 = cur1; cur1 = max1; max2 = max(pre2 + nums.at(j), cur2);//求max2 pre2 = cur2; cur2 = max2; } return max(max1, max2); }
题目:House Robber III
The thief has found himself a new place for his thievery again. There is only one entrance to this area, called the "root." Besides the root, each house has one and only one parent house. After a tour, the smart thief realized that "all houses in this place forms a binary tree". It will automatically contact the police if two directly-linked houses were broken into on the same night.
Determine the maximum amount of money the thief can rob tonight without alerting the police.
Example 1:
3 / 2 3 3 1
Maximum amount of money the thief can rob = 3 + 3 + 1 = 7.
Example 2:
3 / 4 5 / 1 3 1
Maximum amount of money the thief can rob = 4 + 5 = 9.
题意:
按照树形结构排列的房屋,小偷如果同一天偷了相连的房屋就会报警,要求求出今晚最大偷取金额。
思路:
树形结构,一般考虑递归的思路,关键在于偷不偷根节点的对应的房屋。
如果偷根节点,则左右子树的树根节点不能偷取;
如果不偷根节点,则左右子树的根节点可以偷取;
所有每棵子树应该项它的父节点返回偷取根节点时和不偷取根节点时两种情况的结果。
于是就有下面的程序:
/** first 表示偷取根节点; second表示不偷取根节点; **/ pair<int, int> LeetCode::rob(TreeNode* root){ if (!root)return{ 0, 0 }; auto left = rob(root->left);//左子树的结果 auto right = rob(root->right);//右子树的结果 //返回是否偷取当前root节点的两种情况的最优解 return{ left.second + right.second + root->val, max(left.first, left.second) + max(right.first, right.second) }; } int rob(TreeNode* root) { auto p = rob1(root); return max(p.second, p.first); }