1.直接的な思考方法
class Solution {
public int maxArea(int[] height) {
if(height==null||height.length==0||height.length==1){
return 0;
}
int max=0;
for(int j=0;j<height.length;j++)//起点
{
for(int i=1;i<=height.length-1;i++){
//控制底边的长度。
if(j+i<height.length){
int water = Math.min(height[j],height[j+i])*i;
if(max<water)
max = water;
}else
break;
}
}
return max;
}
}
一度は受け入れますが、効率は次のとおりです。
時間の複雑さがO(N 2)に達したことは間違いありません。
2.動的計画法
清華氏によると、動的な計画手順は次のとおりです。
- 1.ステータスを確認する
状態を決定する鍵は
、最後のステップを見つけ、最後のステップから副問題の構造を導き出すことです。
この質問では、最終的な結果として、水を最大限に活用する2つのエンドポイント、ai、aj、およびresが見つかりました。それで、彼女の最後のステップは何でしたか?最後のステップでは、これらの2つのエンドポイントまたはエンドポイントの1つを探す必要があります。つまり、下付きの動きがあります。したがって、副問題があります。我们找当前的ai,aj,需要找到上一次的某两个端点a1,a2,她的盛水量不是最大的。(如何知道不是最大的,我们需要一个记录量,记录当前的最大量,即res)才会出现下标的移动。
結果は次のとおりです。
-
(a[i],a[j])<-(a[i-1],a[j]),if(a[i-1]<a[j])
-
(a[i],a[j])<-(a[i],a[j+1]),if(a[i]>a[j+1])
したがって、a [i] [j]が計算されるとき、計算される現在の最大値はresであると推定できます。次に、resがグローバルな最大値であるかどうかを判断できません。他のエンドポイントの値を計算する必要があります。それで、添え字を移動する必要があります、それはそれを移動する方法ですか?height [i] <height [j]の場合、移動する添字はiでなければなりません。
含まれる水の量は、
2つのポインタが指す数値の小さい方*ポインタ間の距離によって決定されるため
です。数字の大きい方のポインターを動かすと、前者の「2つのポインターが指している数字の小さい方の値」が増えず、後者の「ポインター間の距離」が短くなるため、この積が減ります。次に、それは最大量を見つけるための私たちの需要を満たしていません。したがって、数字が大きい方のポインタを動かすのは無理です。したがって、数字の小さい方にポインタを移動します。
状態を定義し、配列表現を開きます。特に、開かれた配列の次元とサイズも考慮する必要があります。
- 2.再帰方程式
res = min(res、(ji)* min(height [i]、height [j])); - 3.初期条件と境界条件
初期条件は、この可能性があることですが、計算することはできず、同時に再帰に使用する必要があります。
この質問には境界がありません。初期条件:水を保持するには2つのエンドポイントが必要です。したがって、height.length <= 1、-1を返します。 - 4.計算シーケンス、つまり値を使用する場合、その必要性が導入されました。ここでは何も考慮しません
上記の4つのステップを実行して初めて、コードの記述を開始できます。
class Solution {
public int maxArea(int[] height) {
if(height.length<=1)
return -1;
int i = 0,j=height.length-1,res = 0;
while(i<j){
int min = Math.min(height[i],height[j]);
res = Math.max(res,(j-i)*min);
if(height[i]<height[j]){
i++;
}else j--;
}
return res;
}
}
公式ソリューション(デュアルポインタ方式)をご参照ください。動的プログラミングの扉に触れたのは初めてです。