萬用字元——*可以當空串或任意串(一)
題目分析:
s = "acdcb", p = "a*?b";
a * ? b
T F F F F
a F T T F F
c F F T T F
d F F T T F
c F F T T F
b F F T T T
s內容固定,唯有p中?和*的情況特殊,?其實最簡單,直接當匹配即可,*要特殊對待
1.p.charAt(j - 1) != '*'
就簡單了 要麼一樣 要麼p是? 且左上相等
dp[i][j] = (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') && dp[i - 1][j - 1];
2.p.charAt(j - 1) == '*'
s = s[0, i] = "acdcb" p = p[0, j] = "a*"為例
此刻關心 三種情況
2.1.dp[i - 1][j - 1] *當0個
2.2.dp[i][j - 1] *當1個
2.3.dp[i - 1][j] *當多個
dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i - 1][j - 1];
這裡可以簡化一下
因為在這個式子的遞推方式下
上方dp[i - 1][j]和 左上方dp[i - 1][j - 1] 有一些特殊關係
首先上方 也就是j不變,所以p.charAt(j - 1) == '*' 成立
dp[i - 1][j] = dp[i - 2][j] || dp[i - 1][j - 1] || dp[i - 2][j - 1];
可以看到 左上方結果dp[i - 1][j - 1] 已經被"或"進了上方結果dp[i - 1][j]中
所以左上方可以忽略 寫成
dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
PS:左方結果就沒有這個關係了,因為左方j已經變了 p.charAt(j - 2) 不一定等於 '*'。
解法一:
public static boolean isMatch(String s, String p) {
int m = s.length(), n = p.length();
boolean [][]dp = new boolean[m + 1][n + 1];
dp[0][0] = true;
for (int i = 1; i <= n; ++i) {
if (p.charAt(i - 1) == '*') dp[0][i] = dp[0][i - 1];
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p.charAt(j - 1) == '*') {
dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
} else {
dp[i][j] = (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?') && dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
解法二:
/**
* O(m*n) 貪心 回溯
* 回溯部分:
* 本質就是遇到*就挨個嘗試讓*從空串開始用,之後繼續,
* 如果之後配不上,可能是*用錯了,讓*多配一個,sp分別回溯再試
* 貪心部分:
* 只用關心最後一個*
* 如果之前的*和最後一個*之間沒有非*字母,也就是連續的全是*,那麼可以當成一個*,也就成了關心最後一個*
* 如果之前的*和最後一個*之間有非*字母,也就是*(非*,可能是普通字母a,也可能是?)*,配到最後一個*,表示之前的非*都被消耗了,是最理想情況,絕對不用回溯。
*/
public static boolean isMatch(String s, String p) {
int sIndex = 0, pIndex = 0, match = 0, starIdx = -1;
while (sIndex < s.length()){
if (pIndex < p.length() && (p.charAt(pIndex) == '?' || s.charAt(sIndex) == p.charAt(pIndex))){
sIndex++;
pIndex++;
}
else if (pIndex < p.length() && p.charAt(pIndex) == '*'){
/**
* 儲存p中最後出現的*位置
*/
starIdx = pIndex;
/**
* 儲存s中遇到最後*時候的字元位置
*/
match = sIndex;
/**
* 只讓p位置++因為*可以當空串,所以s的不能被跳過一個
*/
pIndex++;
}
/**
* 沒配上,如果之前p出現過*,那麼可能是*沒用對,回溯再試
*/
else if (starIdx != -1){
/**
* p的最後一個*的上一次配法不行 要嘗試躲讓*配一個
* 也就是匹配回溯了
*/
match++;
/**
* s p位置進行相應回溯 s回溯到match位置 + 1 p回溯到最後一個*後方
*/
pIndex = starIdx + 1;
sIndex = match;
}
/**
* p不是*也沒配上 GG
*/
else return false;
}
/**
* 上方保證了s被配完
* 因為*可以被當空串,所以s配完後 如果p後面有多餘的*是依然可以配上的
*/
while (pIndex < p.length() && p.charAt(pIndex) == '*')
pIndex++;
return pIndex == p.length();
}
相關文章
- Java中空串和null串的區別JavaNull
- 用trim去掉字串末尾的任意字元字串字元
- 順序結構儲存串實現串萬用字元匹配的演算法字元演算法
- DB2的字元型欄位,NULL與空串DB2字元Null
- java_求列舉所有的連續(或單個字元)的子串.Java字元
- 從一串字串中匹配URL地址 正則 (可以沒有http或https開頭)字串HTTP
- mknod - 建立塊專用或字元專用檔案字元
- 【每日一題】無重複字元的最長子串每日一題字元
- 用CSS畫出一個任意角度的扇形,可以寫多種實現的方法CSS
- 可以任意定製導航欄背景的一個思路
- 刨根問底:物件也可以當方法用?物件
- 如何Docker化任意一個應用Docker
- 無重複字元的最長子串字元
- linux|批量建立檔案、資料夾或刪除——萬用字元Linux字元
- 雙子串最大異或 題解
- 用 PHP 在 力扣 上演算法 [無重複字元的最長子串]{一天一更}PHP力扣演算法字元
- Python3 - 用Shell萬用字元匹配字串Python字元字串
- [MYSQL-8]用萬用字元進行過濾MySql字元
- java無重複字元的最長子串Java字元
- 3 無重複字元的最長子串字元
- 源資料檔案(.csv)中的空格串和空串對pandas讀取結果的影響
- 一文了解萬用字元SSL證書字元
- 二叉樹的儲存(輸入一串字元)與遍歷二叉樹字元
- 萬用字元詳解字元
- Linux萬用字元Linux字元
- Linux 萬用字元Linux字元
- 藍橋杯-從串中取三個不同字元字元
- 3. 無重複字元的最長子串字元
- 將一個字串中含有全形的數字字元、字母、空格或'%+-()'字元轉換為相應半形字元字串字元
- 重複輸出字元或字串字元字串
- MySQL是如何做到可以恢復到任意一秒狀態的?MySql
- Ubuntu萬用字元的使用Ubuntu字元
- 命令列萬用字元教程命令列字元
- RabbitMQ-萬用字元模式MQ字元模式
- dataframe 萬用字元篩選字元
- 泛型概述-萬用字元泛型字元
- SQL Like萬用字元使用SQL字元
- java的classpath萬用字元Java字元