一般的な考え方:
実際には、本質は「祈るシーケンス番号」です。明らかに、この質問を行うには通常、動的計画で、番号を尋ねています。
この質問と「最長共通部分列を求める」(https://blog.csdn.net/m0_38033475/article/details/79492786は)やや似ています。同様に、このです:シーケンスが不連続であることができます。この質問は、文字列であるすべての部分文字列を含んでいて、尋ねなければならない「とする数値/ケース」;最長共通部分列が最長の同じ配列の長さを見つけるために、単に二つの配列である:違いがあることですむしろ長さよりも。
これら二つの質問をより面白くしているコントラスト:
- 最長共通部分列のアプローチ:
for(int i=1;i<=s1.size();i++)
{
for(int j=1;j<=s2.size();j++)
{
if(s1[i]==s2[j])
dp[i][j] = dp[i-1][j-1] + 1;//一定是这最后一个字母来作为公共子序列的结尾
else
dp[i][j] = max(dp[i][j-1],dp[i-1][j]);//一定不是它做结尾,则看之前的情况谁长谁上
}
}
- タイトル、系列の数:(祈る考える「数/状況」からの注意ではなく、長さ!)
我々は、二次元アレイ必要I文字列番号jが発生している長さの文字列の長さを記録するDP(I)〜(j)をサブストリングの長さを保持し、ヘッドの長さがカウントされると、トラバース最長の文字列が再びサブ文字列の計算開始の少し長さを追加する一方で、同じ、文字列の長さを増加させます。
まず、ので、(ストリングの文字列の長さが0のとき、数は1である文字列の長さが0であるとき、常にあり、数が全て0である1、部分文字列の長さが0のとき、行列を初期化する必要があります彼らは)等しい、空になっています。次に、別の最後の文字とストリングの場合、文字列の最後の文字、新しい文字列を追加手紙がない新たな可能性についての説明は、両方のは、短い文字列の親の出現数のサブストリングを使用することができますので、DP(I )(J)= DP(I)、(J-1) 。最後の手紙と同じ親の文字列の部分文字列の最後の文字に加え、文字の新しい女性の文字列の記述が新たな可能性をもたらした場合、我々は唯一のDP(I)(J-1をカウントしていない )、 だけでなく、新たなカウント可能性。だから、私たちは新たな可能性を追加する必要があり、これらすべての可能性に相当し、最後も手紙をサブストリングこの最後の文字列の母でもない、ストリングの数が表示され、実際に、それの新たな可能性を計算しますか。従って、DP(I)(J)は、DP(I)(1-J)+ DP(1-I)、(J-1)=。
私は理解:S [J]のために!= T [i]は言うまでもなく、この母親を添加した場合の数のように、新しい文字この文字列を追加しませんでした。しかし等しいため、例元の数は確かに考慮すべきですが、また皆を追加したいと思いますそうDP用の[I-1] [jを、共通のシーケンス番号の最終的な位置は、このデッド設定されている、すなわち、共通のシーケンスを終了するマスタストリング、この番号を追加する -1] ここですべての数(同じ長さ、ケースの同じ数!)
プログラミングの注意:
① 初期DPの配列は非常に重要であり、優れたオーダーの始まりのための重要な条件、良い初期化
②それは、このI-1が含まように、それはまだ、この質問の最長共通部分列を求めているかどうかをインデックスが最初から横断する、それが文字列は1から預金をするようになった前に言うことですが、実際には唯一の時間T [I-1]、S [J-1]缶を比較する比較器。
③ 私たちは集中しなければならないプログラミング!!バグを見つけられませんでした長い時間のための事前の書面S [I-1]。。。。
ACコード:
class Solution {
public:
int numDistinct(string S, string T)
{
int dp[2000][2000]; //dp[i][j]:i表示子串长度,j表示母串长度
//dp数组初始化
for(int i=0;i<2000;i++)
{
for(int j=0;j<2000;j++)
{
dp[i][j]=0;
dp[0][j]=1; //子串长度为0,即母串删去所有字符,出现1次
}
}
int len_t = T.size();
int len_s = S.size();
for(int i=1;i<=len_t;i++)
{
for(int j=1;j<=len_s;j++)
{
if(T[i-1]!=S[j-1])
dp[i][j] = dp[i][j-1];
else
dp[i][j] = dp[i][j-1] + dp[i-1][j-1]; //新增最后一个共同字符都定死到母串最后一个新字符的可能情况数
}
}
return dp[len_t][len_s];
}
};
次の日、私たちは非常によく似たトピックを行うだけでなく、プログラムの数を見つけます。
一般的な考え方:
すぐに彼は解決策を求めて、動的計画の実践の数と思っただけで、この新しいキャラクタの現在のためには、単一の単語(DP [I] + = dpと表すことができ 、[I-1])OR (DPとの組み合わせを[I ] + DP = [I-2])。
しかし、まだのようないくつかの特殊なケースを検討欠けています:
- この新しい文字が「0」である場合には、それだけでは、単語を表現することはできません、以前と組み合わせる必要があります。
- なぜなら、動的プログラミングDPを設定する必要があるの[0] = 1が、文字列が空の場合、実際に、出力文字列が0で開始された場合、また、出力0の任意の単語を表すことができない、また0であるべきです。
ACコード:
class Solution {
public:
int numDecodings(string s) {
if(s=="")
return 0;
if(s[0]=='0')
return 0;
long long dp[5000]={0};
dp[0]=1;
dp[1]=1;
int len = s.size();
for(int i=2;i<=len;i++)
{
if(s[i-1]>'0')
dp[i] = dp[i-1]; //单个数字表示一个单词(还是有前提:不能为0)
if((s[i-2]=='1' && s[i-1]<='9')||(s[i-2]=='2' && s[i-1]<='6')) //可以和前一个数字组合表示一个单词
{
dp[i] += dp[i-2];
}
}
return dp[len];
}
};