leetcode309売買銘柄

まず、徹底的なフレームワーク

まず、考え方は同じです:どのように徹底的な?ここでは、物品の再帰の徹底的なアイデアや考えは同じではありません。

実際には、再帰は、あなたが読みやすさも非常に良いですが、誤って作られ、それ投げた再帰的に困難に遭遇した私たちは一歩前進であることを考えるのが論理的です。欠点は間違いたら、あなたは簡単にエラーの原因を見つけていないということです。例えば、物品の再帰的な解決策は、冗長が計算されている必要がありますが、それを見つけるのは容易ではありません。

そしてここで、我々は網羅的であるように、再帰的な考えを持っていないが、「ステータス」網羅を使用します。具体的には、私たちは毎日、その後、対応する各「状態」を見つけ、いくつかの可能な「ステータス」の合計を表示するには「の選択肢を。」私たちは、すべての「状態」を排出したい、目的は対応に応じ網羅「選択」のステータスを更新することです。それは限り、あなたは「ステータス」と「選択」のライン上に2つの単語を覚えているように、ここではそれがどのような実用的な動作を理解することは容易である、抽象的に聞こえます。

状態1における1つの状態のためのすべての値:
状態2における状態2の全ての値のための:
のために...
DP [状態1] [状態2] [...] =メリット(オプション1、オプション2 .. 。)
たとえば、3毎日「を選択し、」この問題があります:買い、売り、無操作、我々が購入、販売、3つのオプションを表して休みます。しかし、問題は、任意に、あなたが購入した後に売却しなければならないので、毎日の3つのオプションを選択する必要がありますの販売後に購入することができない、です。その後、残りの部分は、2つの状態を操作する必要があり、一つは買いの後、残り(株式を保有)で、1は、販売後に(株式を保有していない)残りの部分です。そして、忘れてはいけない、私たちは、あなただけのk> 0の前提の下で動作することができ買うことを、取引kの数が限られています。

非常に右の複雑な、恐れることはありません、ここで我々の目的は、単に網羅され、あなたがより多くのステータスが、実行する老婦人は、リストされたすべてのシャトルです。この質問3への「ステータス」は、最初の日数であり、第二は、トランザクションの最大数が許可され、そして第三は、国家の残りの部分の前に言うことである(現在の状態で保持され、我々は1がホルダーを表し使用することをお勧めします0手段保持無し)。その後、我々は3次元配列は、状態のこれらのタイプのすべての組み合わせにインストールすることができます使用します。

dp[i][k][0 or 1]
0 <= i <= n-1, 1 <= k <= K

n個の日数は、大きなKは、トランザクションの最大数である
すべて、完全にN×K×2つの状態この問題を網羅取得することができます。

for 0 <= i < n:
for 1 <= k <= K:
    for s in {0, 1}:
        dp[i][k][s] = max(buy, sell, rest)

そして、私たちはそれぞれの状態の意味を記述するために、自然言語を使用することができ、そのようなDPの意味[3] [2] [1]です、今日は三日目は、私は今の株式を保持する必要がある2倍の最大値を有します取引。別の例のDP [2] [3] [0]手段は:今日は二日目で、私は今の株式を保有する必要はありません、3トランザクションまで持っています。右、理解しやすいのですか?

どのくらいの利益最も最後の日である[K] [0]、Kトランザクションの最大、 - 私たちは究極の答えはDP [1 n]が見つけたいと思います。読者はなぜDP求めることができる[N - 1] [K] [1]?[1]まだ在庫を保持している手を表し、[0]株式の手を表すが販売されたので、後者の結果として得られる利益が前者よりも大きくなければならないことは明らかです。

「ステータス」を解釈する方法を覚えておいてください、あなたが理解しにくいと感じたらどこ、それは自然言語に翻訳理解しやすいです。

第二に、状態遷移フレーム

今、私たちは「ステータス」網羅を完了している、我々は、更新する方法をどのような「選択」、各「状態」を考えるようになった「状態に。」「保留状態」を見て状態遷移図を描くことができます。

あなたは明確に転送が来たか(0と1)各状態、このマップを通して見ることができます。このグラフによると、我々は状態遷移方程式について書いてあります。

 dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
          max(   选择 rest  ,           选择 sell      )

説明:今日の株式を保有していない、二つの可能性があります:
私は今日保有していなかったので、私は、昨日開催した後、今日の残りの部分を選択しなかったのいずれか、
私は昨日の株式を保持しますが、今日の私の販売のいずれか、および私は今日の株式を保有していません。

dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
          max(   选择 rest  ,           选择 buy         )

説明:今日の株式を保有、二つの可能性があります:
私は今日の株式を保有する必要があるので、私は、昨日の株式を保有して、今日の残りの部分を選択することになるのいずれか、
私は昨日、これを保持していないが、今日私が購入することのいずれかを選択します今日のように、私が株式を保有します。
あなたが購入した場合、この説明は、非常に明確にする必要があり、[i]を販売する場合、我々は利益の増加の価格を与える必要があり、利益から[i]の価格が差し引かれます。今日の最大の利益は大きい方の両方を選択することが可能です。そして、制限kに注意を払うときに、同じもちろん、あなたはまた、マイナス1で販売することができ、我々は、購入時に選択したのk 1を減少させ、それが十分に理解されています。

状態遷移方程式:今、私たちは、最も困難な段階での動的プログラミングを完了しました。コンテンツはあなたが理解することができます前にした場合は、すでに長いラインでこのフレームワークセットなどとして、すべての問題を殺すことができます。しかし、最後のaが少し悪化し、それが最も簡単なケースであるベースケースを、定義することです。

  dp[-1][k][0] = 0

説明:私はゼロであるので、私は= -1まだ始まっていない手段をするので、この時間は、当然のことながら、利益はゼロです。
DP [-1] [K] [ 1] = -Infinity
説明:起動していない場合、負の無限大を表すことができない株式を保持することは不可能です。
DP [I] [0] [ 0] = 0
説明:kがあるため、最初からあり、もちろんこの時点で利益がゼロである、トランザクションは許可しなかったこと= 0はkのようにします。
DP [I] [0] [ 1] = -Infinityは
説明:トランザクションを許可せず、負の無限大で表現することができない株式を保持することは不可能です。
集計上記状態遷移方程式:

  base case:
  dp[-1][k][0] = dp[i][0][0] = 0
  dp[-1][k][1] = dp[i][0][1] = -infinity

状態遷移式:
DP [I] [K] [0] = MAX(DP [I-1] [K] [0]、DP [I-1] [K] +料金[I] [1。])
DP [ I] [K] [1] = MAX(DP [I-1] [K] [1]、DP [I-1] [K-1] [0] -価格[i])と
読者が求めることができる、この配列のインデックスは-1、まだそれをプログラミングする方法、それを表現する方法を負の無限大?これらは、達成するための多くの方法がありますが、詳細です。今、完全なフレームワークが完了している、あなたは、コンクリートを開始することができます。

第三に、スパイクのタイトル

最初の質問で、k = 1

直接ベースケースによれば、状態遷移方程式を設定し、いくつかの単純化を行うことができます。

  dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][1][1] + prices[i])
  dp[i][1][1] = max(dp[i-1][1][1], dp[i-1][0][0] - prices[i]) 
        = max(dp[i-1][1][1], -prices[i])

説明:K =ベース場合0、そうDP [I-1] [0] [0] = 0。

Kは、現在1であると、kは状態がシフトに影響を及ぼさない、変更されないことが見出されています。
さらに、すべてのK除去するために簡略化することができる:
DP [I] [0] = MAX([1] DP [I-1] [0]、DP [I-1] +料金[I])
。DP [I]を[1 = MAX(DP [I- 1] [1]、-prices [i])と
ダイレクトライトコード:

 int n = prices.length;
 int[][] dp = new int[n][2];
 for (int i = 0; i < n; i++) {
  dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
  dp[i][1] = Math.max(dp[i-1][1], -prices[i]);

}
戻りDP [N - 1] [0];
iは=ときに明らかに0 DP [I-1]が合法ではありません。私たちは、処理のための基本ケースIを持っていないためです。この治療法は、次のことができます。

 for (int i = 0; i < n; i++) {
  if (i - 1 == -1) {
    dp[i][0] = 0;
    // 解释:
    //   dp[i][0] 
    // = max(dp[-1][0], dp[-1][1] + prices[i])
    // = max(0, -infinity + prices[i]) = 0
    dp[i][1] = -prices[i];
    //解释:
    //   dp[i][1] 
    // = max(dp[-1][1], dp[-1][0] - prices[i])
    // = max(-infinity, 0 - prices[i]) 
    // = -prices[i]
    continue;
  }
 dp[i][0] = Math.max(dp[i-1][0], dp[i-1][1] + prices[i]);
 dp[i][1] = Math.max(dp[i-1][1], -prices[i]);
 }
return dp[n - 1][0];

第一の問題は解決するが、この処理の基本ケースは非常に面倒であり、約状態遷移方程式のメモ、新しい状態だけ隣接する状態をとり、実際には、全体ではなくDPアレイ、状態隣接するを格納するための唯一の変数でありますあなたは宇宙の複雑さO(1)を置くことができますので、十分に:

  // k == 1
  int maxProfit_k_1(int[] prices) {
  int n = prices.length;
// base case: dp[-1][0] = 0, dp[-1][1] = -infinity
int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
  for (int i = 0; i < n; i++) {
    // dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
    dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
    // dp[i][1] = max(dp[i-1][1], -prices[i])
    dp_i_1 = Math.max(dp_i_1, -prices[i]);
  }
 return dp_i_0;
  }

二つの方法は同じですが、このプログラミング方法の多くは単純です。状態遷移方程式の前には、ガイドがない場合でも、それは確かに読まれていません。フォローアップの質問は、私は主にソリューションのOのこのスペースの複雑さ(1)を書きました。

2番目の質問で、k = +無限大

1と同じである - kは正の無限大である場合は、kおよびkは考えることができます。これは、このフレームワークを書き換えることができます。

  dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i])
  dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i])
        = max(dp[i-1][k][1], dp[i-1][k][0] - prices[i])

我々は、アレイkはk個の状態を記録する必要がないこと、変更されていないことが判明:
[-I 1] DP [I] [0] = MAX(DP [-I 1] [0]、DPを[ 1] +料金[I])
。。。。DP [I] [1] = MAX(DP [-I 1] [1]、DP [-I 1] [0] -価格[I])を
直接コードに変換されます。

 int maxProfit_k_inf(int[] prices) {
 int n = prices.length;
 int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
 for (int i = 0; i < n; i++) {
    int temp = dp_i_0;
    dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
    dp_i_1 = Math.max(dp_i_1, temp - prices[i]);
  }
  return dp_i_0;
  }

冷却と3番目の質問、K = +無限

各販売後の取引を継続するために、1日待ちます。限り状態遷移方程式缶のタイトルに統合され、この機能のように:

  dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
  dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i])

説明:私はときに私-2の代わりにI-1の状態遷移、から選択された日を買います。
コードに翻訳:

  int maxProfit_with_cool(int[] prices) {
  int n = prices.length;
  int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
  int dp_pre_0 = 0; // 代表 dp[i-2][0]
  for (int i = 0; i < n; i++) {
    int temp = dp_i_0;
    dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
    dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]);
    dp_pre_0 = temp;
  }
  return dp_i_0;
 }

料と第四の問題で、k = +無限大

各トランザクションのための手数料を支払うために、限り料金は利益から差し引かれるようすることができます。式を書き直し:

 dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
 dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i] - fee)

説明:価格上昇に相当買い株。
最初のカットでは株価の減少を販売する等価である、家のと同じタイプです。
直接コードに変換:

  int maxProfit_with_fee(int[] prices, int fee) {
  int n = prices.length;
  int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
  for (int i = 0; i < n; i++) {
    int temp = dp_i_0;
    dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
    dp_i_1 = Math.max(dp_i_1, temp - prices[i] - fee);
  }
  return dp_i_0;
  }

第五の問題、K = 2

K = 2と被写体若干異なる前場合、上記関係の場合は大きすぎるとKではないからです。Kは、正の無限大であり、状態遷移Kは問題ではない;またはK = 1最後に存在するのは意味がなくなるまで、ベースケースとK = 0は、耐えます。

この質問K = 2、kは顕著なの処理上の正の整数、kの場合の任意のトークバックです。書き込みはその理由を分析しながら、私たちは、直接コードを記述します。

元の動的移動式無簡略化
DP [I] [K] [ 0] = MAX(DP [I-1] [K] [0]、DP [I-1] [K] [1] +料金[I])
DP [I] [K] [1] = MAX(DP [I-1] [K] [1]、DP [I-1] [K-1] [0] -料金[I ])
前のコードに基づいて、我々はこのような許可された書き込みコード(間違った)のためにそれを取ることがあります。

 int k = 2;
 int[][][] dp = new int[n][k + 1][2];
 for (int i = 0; i < n; i++)
  if (i - 1 == -1) { /* 处理一下 base case*/ }
  dp[i][k][0] = Math.max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
  dp[i][k][1] = Math.max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
 }
  return dp[n - 1][k][0];

なぜ間違っていますか?私は、状態遷移方程式はそれを書く輝いていませんか?

「徹底的な枠組み」、それ以前の概要を覚えていますか?我々は、すべての状態を排出しなければならないこと。実際には、すべてのすべての状態で私たちの以前のソリューションは、対象kがアウトに簡略化されている直前に、網羅します。この質問は、kの影響を排除しない、kは網羅的であることである必要があります。

 int max_k = 2;
 int[][][] dp = new int[n][max_k + 1][2];
 for (int i = 0; i < n; i++) {
 for (int k = max_k; k >= 1; k--) {
     if (i - 1 == -1) { 
        /* 处理 base case */
        dp[i][k][0] = 0;
        dp[i][k][1] = -prices[i];
        continue;
    }
    dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
    dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);
 }
 }

// n個の網羅×max_k×2つの状態を正しく。
DP返す[N - 1] [ max_k] [0];
あなたが理解していない場合は、あなたが最初のポイントに戻ることができ、再読み込み味「の徹底的な枠組み」。

ここで、ループは、直接のマニュアルK = 1及び2に列挙されてもよいことができないので、kが比較的小さい範囲です。

  dp[i][2][0] = max(dp[i-1][2][0], dp[i-1][2][1] + prices[i])
  dp[i][2][1] = max(dp[i-1][2][1], dp[i-1][1][0] - prices[i])
  dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][1][1] + prices[i])
  dp[i][1][1] = max(dp[i-1][1][1], -prices[i])

 int maxProfit_k_2(int[] prices) {
 int dp_i10 = 0, dp_i11 = Integer.MIN_VALUE;
 int dp_i20 = 0, dp_i21 = Integer.MIN_VALUE;
 for (int price : prices) {
    dp_i20 = Math.max(dp_i20, dp_i21 + price);
    dp_i21 = Math.max(dp_i21, dp_i10 - price);
    dp_i10 = Math.max(dp_i10, dp_i11 + price);
    dp_i11 = Math.max(dp_i11, -price);
   }
  return dp_i20;
 }

状態遷移方程式と明確なガイダンスを意味する変数名がありますが、私はあなたが理解することは非常に簡単であると信じています。実際には、我々は、トリックすることができ、B、C、Dの中に4つの変数を置きます。人々が見たときにあなたのコードが混乱して警戒されるように、あなたは尊重しなければなりません。

質問6、K =任意の整数

= 2寝具k上のタイトルでは、この問題は、質問の区別を欠いのソリューションでなければなりません。しかし、もともとk値に渡された超メモリエラーは、あまりにも非常に大きく、DP配列になりますがあります。今それについて考える、取引数kがするまでがありますか?

トランザクションは、少なくとも2日間、買いと売りで構成されています。有効な限界kを超えた場合、そこには結合効果がなく、そしてkに相当= +無限大、2を超えN /べきではないので。この状況は、前に前に解決されます。

直接コードの再利用の前に:

  int maxProfit_k_any(int max_k, int[] prices) {
   int n = prices.length;
    if (max_k > n / 2) 
    return maxProfit_k_inf(prices);

   int[][][] dp = new int[n][max_k + 1][2];
   for (int i = 0; i < n; i++) 
    for (int k = max_k; k >= 1; k--) {
        if (i - 1 == -1) { /* 处理 base case */ }
        dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
        dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);     
    }
return dp[n - 1][max_k][0];
  } 

これまでのところ、すべてを解決するために、状態遷移方程式によって6つのトピック。

第四に、締結

6株式売買問題スパイク状態遷移式で、複雑な問題の状態遷移方法を解決し、今考えることをどのように伝えるためにこの記事で、右、実際には、あまりにも難しいことではありませんか?これは、より困難に動的なプログラミングの問題の一部となっています。

キーがどのように徹底的なアップデートこれらについて考え、その後、すべての可能な「ステータス」を列挙することである「状態。」通常、これらの状態のDPストレージの多次元配列で、基本ケースから後方に推進し、最終的な状態に進め、始まった、それは我々が答えを望むものです。このプロセスを考えて、あなたはそれの言葉のこの意味での「ダイナミックプログラミング」の少し理解がないのですか?

株取引に特有の、我々は、3つの状態が見つかった3次元配列、または網羅+更新よりも何を使用していますが、我々は大きなポイントと言うことができる、の恐れ「三次元DP」と呼ばれますか?これは偉大な真実は、あなたがすぐそこに優れ、名声と富を見て言います。

だから、私たちは背が高く、様々な名詞に脅迫されることはありません、気の利いたものの役に立たない難しさのない量は、それが生成された基本ルーチンをエスカレートの組み合わせではなかったです。限り、基本的な原理は、アルゴリズムに従っているとして、あなたは、類推により1つのブレークずつを学ぶことができます。

おすすめ

転載: www.cnblogs.com/wqali/p/12006552.html