title: 【每日一题】LeetCode 213.打家劫舍II - 线性DP
tags:

  • leetcode
  • acwing
  • 每日一题
  • 算法
    abbrlink: cdd03afb
    date: 2021-04-15 18:12:19

LeetCode 213.打家劫舍II

思路

这道题有一道前置题目,即LeetCode 198.打家劫舍,这道前置题目没有环形,是一道常规的线性DP,在每一步都分别判定选和不选的状态即可,而到了本题内,因为是环形的,那么在起始点(终点)的地方就要注意一下,这里起点终点相互影响,所以我们要用分支结构控制一下每个分支的计算的房子,防止少判断

C++代码

  1. class Solution {
  2. public:
  3. int rob(vector<int>& nums) {
  4. int n=nums.size();
  5. if(n==0) return 0;
  6. if(n==1) return nums[0];
  7. if(n==2) return max(nums[0], nums[1]);
  8. int ans=0, f, g;
  9. f=nums[2]; g=0;
  10. for(int i=3;i<n;i++)
  11. {
  12. int lastf=f,lastg=g;
  13. f=lastg+nums[i];
  14. g=max(lastf, lastg);
  15. }
  16. ans=g+nums[0];
  17. f=nums[1]; g=0;
  18. for(int i=2; i<n;i++)
  19. {
  20. int lastf=f, lastg=g;
  21. f=lastg+nums[i];
  22. g=max(lastf, lastg);
  23. }
  24. ans=max(ans, max(f,g));
  25. return ans;
  26. }
  27. };

AcWing 1055.股票买卖

思路I

这道题在蓝桥杯选拔校赛中出现过,贪心的思路也很简单,判断每天比前一天是涨还是跌就好了,如果明天股票会跌那么今天全部卖掉,如果明天股票涨那么就要大量买入,得到的结果一定是最优的。

C++代码I

  1. #include<iostream>
  2. using namespace std;
  3. const int N=1e5+10;
  4. const int INF=0x3f3f3f;
  5. int n;
  6. int a[N];
  7. int main()
  8. {
  9. cin>>n;
  10. for(int i=0;i<n;i++)
  11. cin>>a[i];
  12. int res=0;
  13. for(int i=1;i<=n;i++)
  14. if(a[i]-a[i-1]>0) res+=a[i]-a[i-1];
  15. cout<<res<<endl;
  16. return 0;
  17. }

思路II

这道题正解应该使用DP来实现的,分析下来一共有两个状态要推:

  1. 当前处于未持股状态
    对应的转换有买入和不买入两种处理
  2. 当前处于持股状态
    对应的转换状态就有卖出和不卖出
    由此就可以推出状态转移方程。

C++代码II

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 1e5 + 10, INF = 0x3f3f3f;
  4. int n;
  5. int w[N];
  6. int f[N][2];
  7. int main() {
  8. scanf("%d", &n);
  9. for (int i = 1; i <= n; ++i) scanf("%d", &w[i]);
  10. f[0][1] = -INF;
  11. for (int i = 1; i <= n; ++i) {
  12. f[i][0] = max(f[i - 1][0], f[i - 1][1] + w[i]);
  13. f[i][1] = max(f[i - 1][1], f[i - 1][0] - w[i]);
  14. }
  15. printf("%d\n", f[n][0]);
  16. return 0;
  17. }