[LeetCode] House Robber
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
分析一:DP问题。如果偷盗第i家,那么偷盗当前第i家获得的最大收益是偷盗[1~i-2]中的某一家获得的最大收益再加上当前这一家的金钱数目。不能偷盗相邻的,也就不能偷盗第i-1家。递推公式为profit[i] = max{profit[1], profit[2], ..., profit[i-2]},没有i-1因为不能偷盗相邻家。
时间复杂度O(n2),空间复杂度O(n)
class Solution { public: int rob(vector<int>& nums) { vector<int> profit(nums.size()); int max_profit = 0; for (int i = 0; i < nums.size(); i++) { profit[i] = nums[i]; int temp_max_profit = 0; for (int j = i - 2; j >= 0; j--) { if (profit[j] > temp_max_profit) temp_max_profit = profit[j]; } profit[i] = temp_max_profit + nums[i]; if (profit[i] > max_profit) max_profit = profit[i]; } return max_profit; } };
分析二:
我们从上述分析可以看到,如果记录[1~i-2]的最大值的话,就能避免每次偷i家的时候的循环查找操作。我们将这个这个最大值记作pen_profit。每次偷完一家都要更新pen_profit后续使用。
时间复杂度O(n),空间复杂度O(n)
class Solution { public: int rob(vector<int>& nums) { vector<int> profit(nums.size()); int max_profit = 0; int pen_profit = 0; for (int i = 0; i < nums.size(); i++) { profit[i] = pre_profit + nums[i]; if (i - 1 >= 0 && profit[i-1] > pen_profit) pen_profit = profit[i-1]; if (profit[i] > max_profit) max_profit = profit[i]; } return max_profit; } };
分析三:我们已经把时间复杂度降下来了。能不能再把O(N)的空间复杂度降下来呢。目前profit数组(vector)的作用有两个:更新pen_profit和用来与max_profit作比较。我们看到更新pen_profit一直使用的是profit[i-1],所以如果我们能一直维持一个变量用来存储最新的profit[i-1]的话,我们就可以放弃数组了。这里我们用pre_profit表示profit[i-1]。profit数组与max_profit作比较的操作每次使用的是profit[i]也就是每次循环计算出来新鲜的profit值。那么就用curr_profit保存这个刚刚计算出来的profit。这样在这一步就不用profit的vector了。
时间复杂度O(n),空间复杂度O(1)
class Solution { public: int rob(vector<int>& nums) { int max_profit = 0; int pen_profit = 0; int pre_profit = 0; for (int i = 0; i < nums.size(); i++) { int curr_profit = pen_profit + nums[i]; if (i - 1 >= 0 && pre_profit > pen_profit) pen_profit = pre_profit; if (curr_profit > max_profit) max_profit = curr_profit; pre_profit = curr_profit; //更新pre_profit } return max_profit; } };