思路:給定乙個字串 s 和乙個字串 t,計算在 s 的子串行中 t 出現的個數。乙個字串的乙個子串行是指,通過刪除一些(也可以不刪除)字元且不干擾剩餘字元相對位置所組成的新字串。(例如,「ace」 是 「abcde」 的乙個子串行,而 「aec」 不是)題目資料保證答案符合 32 位帶符號整數範圍。
輸入:s =
"rabbbit"
, t =
"rabbit"
輸出:3
解釋:如下圖所示, 有 3 種可以從 s 中得到 "rabbit" 的方案。
(上箭頭符號 ^ 表示選取的字母)
rabbbit^^
^^^^
rabbbit^^
^^^^
rabbbit^^
^^^^
這一題也屬於兩個字串的匹配問題,需要用到二維動態規劃(這種往往dfs也是可行的,也可以空間優化為一維動態規劃)由於t一定是比s短的,我們先遍歷t再遍歷s,dp[i][j] 代表 t 前 i 字串可以由 s j 字串組成最多個數。初始化動態規劃陣列為st的長度加一,是為了也考慮空串的情況。那麼有:
1.當 s[j-1]
== t[i-1]
, 此時可以選擇匹配當前s的j-
1位置dp[i-1]
[j-1
],也可以選擇跳過前s的j-
1位置dp[i]
[j-1
],這兩種情況都會考慮j-
1列,因為在內迴圈中是在遍歷j,無論是否要取s的j-
1位置,dp[i]
[j]始終會與j-
1位置有關。所以:
dp[i]
[j]= dp[i-1]
[j-1
]+ dp[i]
[j-1];
2.當 s[j-1]
!= t[i-1]
, 只能選擇跳過:
dp[i]
[j]= dp[i]
[j-1
]
另外,還需要進行初始化:
int
dp =
newint
[t.length()
+1][s.
length()
+1];
for(
int j =
0; j < s.
length()
+1; j++
) dp[0]
[j]=
1;
完整**如下:
public
intnumdistinct
(string s, string t)
}return dp[t.
length()
][s.
length()
];}
我們還可以對他進行空間優化:
public
intnumdistinct
(string s, string t)}}
return dp[t.
length()
];}
空間優化需要注意幾點:
1.首先陣列的維度為多少?這裡設定的為t的長度,因為從二維動態規劃陣列就可以看出變化的是第乙個維度,因此保留第乙個維度。
2.其次,二層迴圈的內層應該是t,這是和二維動態規劃不同的,由於dp長度為t的長度,所以外層從0開始,比較字元的時候也要注意應該是s.charat(i) == t.charat(j-1)。
3.另外,初始化dp[0] = 1即可,不然整個更新後陣列仍然都是0。最重要的一點是,內層需要反向遍歷,不然會覆蓋之前的值!!
舉個簡單的例子,有很多題目在使用動態規劃時需要倒著更新,比如119. 楊輝三角 ii,動態規劃的陣列更新需要使用上一層的資料,因此不可以覆蓋:
public list
getrow
(int rowindex)
} list
res = arrays.
aslist
(dp)
;return res;
}
這一題還需要注意的是,要想list res = arrays.aslist(dp) 這一句不報錯,必須將陣列初始化為integer型別。
那麼用int為什麼會報錯呢?因為arrays.aslist()是泛型方法,傳入的物件必須是物件陣列。如果傳入的是基本型別的陣列,那麼此時得到的list只有乙個元素,那就是這個陣列物件int本身。
力扣 不同子串行
給定乙個字串 s 和乙個字串 t s rabbbit t rabbit 計算在 s 的子串行中 t 出現的個數。字串的乙個 子串行是指,通過刪除一些 也可以不刪除 字元且不干擾剩餘字元相對位置所組成的新字串。例如,ace 是 abcde 的乙個子串行,而 aec 不是 此時我們通過矩陣來解決該問題,...
力扣每日一題115 不同的子串行
1.暴力法超時 class solution if i s.size i t.size return 到任意末端返回 if s i t i else return public int numdistinct string s,string t 2.動態規劃 從後往前遍歷 dp i j 代表 s i...
115 不同的子串行
題目.high dp用熟了反而覺得簡單了。s字串增加乙個字元,要麼這個字元與t的最後乙個字元相同,要麼不相同 package main import fmt func numdistinct s string t string int iflen t 0 dp make int len s 1 fo...