Teknologian jakaminen

[Väärien kysymysten kokoelma - Ohjelmointikysymykset] Paras aika ostaa ja myydä osakkeita (4) (Dynaaminen ohjelmointi)

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

Linkki vastaavaan kysymykseen:188. Paras aika ostaa ja myydä osakkeita IV - LeetCode

Niuken vastaavan aiheen linkki:Paras aika ostaa ja myydä osakkeita (4)_Niuke Topic_Niuke.com (nowcoder.com)


1. Analysoi aihe

1、Tilan esitys

Erottaakseen selvemminostaajamyydä, korvaamme senVaraa osakkeitajaei varastossaKaksi osavaltiota.

  • f[i][j] tarkoittaa: Ei. i Päivän päätteeksi se on tehty j kauppa, tällä hetkellä käynnissäVaraa osakkeitaValtion suurin hyöty.
  • g[i][j] tarkoittaa: Ei. i Päivän päätteeksi se on tehty j kauppa, tällä hetkellä käynnissäei varastossaValtion suurin hyöty.

2. Tilasiirtymäyhtälö

varten f[i][j], on myös kaksi tilannetta, joissa i Kun päivä on ohi, valmis j Kauppa käynnissä tällä hetkelläVaraa osakkeitaTila:

  • olla olemassa i-1 Taivaalla, käsissäVaraa osakkeita, ja vaihdettiin j Toisen luokan. 1. päivänä älä tee mitään.Tulot tällä hetkellä ovat f[i - 1][j]
  • olla olemassa i-1 Taivaalla, käsissäei osakkeita, ja vaihdettiin j Toisen luokan.Ensimmäisessäi Kun aurinko laski, ostin osakkeita lippu.Niini Päivän lopussa on osakkeita.Tulot tällä hetkellä ovatg[i - 1][j] - hinnat[i]

Kahdessa yllä olevassa tapauksessa tarvitsemmeenimmäisarvo, joten f:n tilasiirtymäyhtälö on:

f[i][j] = max(f[i - 1][j], g[i - 1][j] - hinnat[i]

varten g[i][j], meillä on seuraavat kaksi tilannetta, joissa voimme i Kun päivä on ohi, valmis j Kauppa käynnissä tällä hetkelläei osakkeitaTila:

  • olla olemassa i-1 Päivänä minulla ei ollut osakkeita käsissäni ja vaihdoin niitä. j Toisen luokan.1. päivänä älä tee mitään .Tulot tällä hetkellä ovatg[i - 1][j]
  • olla olemassa i-1 Aamunkoittopäivänä minulla oli osakkeita käsissäni ja kävin niillä kauppaa. j - 1 Toisen luokan.Ensimmäisessäi Kun paistaa aurinko, laita Osake myytiin.Niini Päivän päätteeksi käymme kauppaa j Toisen luokan.Tulot tällä hetkellä ovat f[i - 1][j - 1] + hinnat[i]

Kahdessa yllä olevassa tapauksessa tarvitsemmeenimmäisarvo,siksi g Tilasiirtymäyhtälö on:

g[i][j] = max(g[i - 1][j], f[i - 1][j - 1] + hinnat[i])

Niiden välinen kauppasuhde on seuraava:


3. Alustus

Koska sitä tarvitaan i = 0 Nykyinen tila, jotta voimme alustaa ensimmäisen rivin.
  • kun sisällä 0 päivää, voi olla vain sisäänKerran ostettuvaltion tulot tällä hetkellä ovat -hinnat[0] ,koskaTämä f[0][0] = - hinnat[0]
  • ottaakseen max Milloin, jotkut olemattomat valtiotEi häiriöitä-toiminto, alustamme ne kaikki seuraavasti -INF(käyttääINT_MIN Laskentaprosessin aikana tulee olemaanylivuotoRiski tässä INF Ota puolet 0x3f3f3f3f , tarpeeksi pieni).

4、Lomakkeen täyttöjärjestys

Täytä jokainen rivi ylhäältä alas, jokainen rivi vasemmalta oikealle ja täytä molemmat taulukot yhdessä.

5、palautusarvo

Palauttaa maksimiarvon myyntitilassa, mutta emme tiedä kuinka monta kertaa sillä vaihdettiin, joten se palauttaa g Suurin arvo taulukon viimeisellä rivillä.


6、optimointi

Tapahtumamme määrä ei ylitä puolta koko päivien määrästä, joten voimme ensin k Käsitellään sitä ja optimoidaan ongelman koko:k = min(k, n / 2)


2. Koodi

  1. //力扣
  2. //【动态规划-二维dp-2个状态】
  3. class Solution {
  4. //f[i][j]:第i天结束后,完成了j次交易,此时处于“买入”状态下的最大利润
  5. //g[i][j]:第i天结束后,完成了j次交易,此时处于“卖出”状态下的最大利润
  6. private:
  7. const int INF=0x3f3f3f3f;
  8. public:
  9. int maxProfit(int k, vector<int>& prices) {
  10. int n=prices.size();
  11. k=min(k, n/2); //优化:处理最多交易次数
  12. vector<vector<int>> f(n, vector<int>(k+1, -INF));
  13. vector<vector<int>> g(n, vector<int>(k+1, -INF));
  14. f[0][0]=-prices[0], g[0][0]=0;
  15. for(int i=1; i<n; i++)
  16. {
  17. for(int j=0; j<=k; j++)
  18. {
  19. f[i][j]=max(f[i-1][j], g[i-1][j]-prices[i]);
  20. g[i][j]=g[i-1][j];
  21. if(j>=1) g[i][j]=max(g[i][j], f[i-1][j-1]+prices[i]);
  22. }
  23. }
  24. int res=0;
  25. for(int j=0; j<=k; j++)
  26. res=max(res, g[n-1][j]);
  27. return res;
  28. }
  29. };
  30. //【动态规划-二维dp-2k+1个状态】
  31. class Solution {
  32. //dp[i][0] -- 没有操作
  33. //下面j为奇数:买入;j为偶数:卖出 (j的范围:1~2k-1)
  34. //dp[i][j] -- 第1~k次买入
  35. //dp[i][j+1] -- 第1~k次卖出
  36. public:
  37. int maxProfit(int k, vector<int>& prices) {
  38. int n=prices.size();
  39. vector<vector<int>> dp(n, vector<int>(2*k+1));
  40. for(int j=1; j<2*k; j+=2)
  41. dp[0][j]=-prices[0];
  42. for(int i=1; i<n; i++)
  43. {
  44. for(int j=0; j<2*k; j+=2)
  45. {
  46. dp[i][j+1]=max(dp[i-1][j+1], dp[i-1][j]-prices[i]);
  47. dp[i][j+2]=max(dp[i-1][j+2], dp[i-1][j+1]+prices[i]);
  48. }
  49. }
  50. return dp[n-1][2*k];
  51. }
  52. };
  1. //牛客
  2. #include <iostream>
  3. #include <cstring>
  4. using namespace std;
  5. const int INF=0x3f3f3f3f;
  6. const int N=1010, M=110;
  7. int prices[N];
  8. int f[N][M], g[N][M];
  9. //f[i][j]:第i天结束后,完成了j次交易,此时处于“买入”状态下的最大利润
  10. //g[i][j]:第i天结束后,完成了j次交易,此时处于“卖出”状态下的最大利润
  11. int main()
  12. {
  13. int n, k;
  14. cin >> n >> k;
  15. for(int i=0; i<n; i++)
  16. cin >> prices[i];
  17. memset(f, -INF, sizeof(f));
  18. memset(g, -INF, sizeof(g));
  19. int res=0;
  20. f[0][0]=-prices[0], g[0][0]=0;
  21. for(int i=1; i<n; i++)
  22. {
  23. for(int j=0; j<=k; j++)
  24. {
  25. f[i][j]=max(f[i-1][j], g[i-1][j]-prices[i]);
  26. g[i][j]=g[i-1][j];
  27. if(j>0) g[i][j]=max(g[i][j], f[i-1][j-1]+prices[i]);
  28. res=max(res, g[i][j]);
  29. }
  30. }
  31. cout << res << endl;
  32. return 0;
  33. }
  34. //值得学习的代码
  35. #include <iostream>
  36. using namespace std;
  37. const int N = 1010, M = 110;
  38. int n, k, p[N];
  39. int f[N][M], g[N][M];
  40. int main()
  41. {
  42. cin >> n >> k;
  43. for(int i = 0; i < n; i++) cin >> p[i];
  44. k = min(k, n / 2);
  45. for(int j = 0; j <= k; j++) f[0][j] = g[0][j] = -0x3f3f3f3f;
  46. f[0][0] = -p[0], g[0][0] = 0;
  47. for(int i = 1; i < n; i++)
  48. {
  49. for(int j = 0; j <= k; j++)
  50. {
  51. f[i][j] = max(f[i - 1][j], g[i - 1][j] - p[i]);
  52. g[i][j] = g[i - 1][j];
  53. if(j >= 1) g[i][j] = max(g[i][j], f[i - 1][j - 1] + p[i]);
  54. }
  55. }
  56. int ret = 0;
  57. for(int j = 0; j <= k; j++) ret = max(ret, g[n - 1][j]);
  58. cout << ret << endl;
  59. return 0;
  60. }

3. Heijastus ja parantaminen

Useat kysymykset, kuten osakkeiden ostaminen ja myyminen, edellyttävät perusteellista perehtymistä ydintietopisteisiin.