LeetCode-1745。パリンドロームパーティショニングIV [パリンドロームパーティショニングIV]-分析とコード[Java]
1.トピック
空でない回文部分文字列に分割できる場合は文字列sを指定し、trueを返す場合は、falseを返します。
文字列が逆方向に読み取られるのとまったく同じように読み取られる場合、それは回文文字列と呼ばれます。
例1:
输入:s = "abcbdd"
输出:true
解释:"abcbdd" = "a" + "bcb" + "dd",三个子字符串都是回文的。
例2:
输入:s = "bcbddxy"
输出:false
解释:s 没办法被分割成 3 个回文子字符串。
促す:
- 3 <= s.length <= 2000
- sには小文字の英字のみが含まれます。
出典:LeetCode(LeetCode)
リンク:https://leetcode-cn.com/problems/palindrome-partitioning-iv
著作権はLeetCodeが所有しています。商用の再版については、公式の承認に連絡してください。非商用の再版については、出典を示してください。
2、分析とコード
1.両端の列挙
(1)考える
最初と3番目の部分文字列の一方の端の間の境界は文字列の最初と最後に固定されているため、もう一方の端の可能な値を最初に見つけてから、真ん中に2番目の文字列があるかどうかを列挙してみてください実行可能解または完全な走査が見つかるまで、回文部分文字列を構成します。
(2)コード
class Solution {
public boolean checkPartitioning(String s) {
char[] c = s.toCharArray();
int len = s.length();
List<Integer> l1list = new ArrayList<>();
List<Integer> l2list = new ArrayList<>();
for (int l1 = 1; l1 < len - 1; l1++) {
if (check(c, 0, l1 - 1))
l1list.add(l1);
}
for (int l2 = len - 1; l2 > 1; l2--) {
if (check(c, l2, len - 1))
l2list.add(l2);
}
for (int i = 0; i < l1list.size(); i++) {
for (int j = 0; j < l2list.size(); j++) {
if (l1list.get(i) < l2list.get(j) && check(c, l1list.get(i), l2list.get(j) - 1))
return true;
}
}
return false;
}
public boolean check(char[] c, int l, int r) {
while (l < r) {
if (c[l++] != c[r--])
return false;
}
return true;
}
}
(3)結果
実行時間:388ミリ秒、
すべてのJava送信でユーザーの5.05%を上回っています。メモリ消費量:37.1 MB、すべてのJava送信でユーザーの97.01%を上回っています。
2.動的計画法
(1)考える
2次元ブール配列dp [i] [j]を設計して、添え字[i、j]を含む部分文字列が回文文字列であるかどうかを記録します。回文部分文字列は対称の中心から両側に拡張することによってのみ取得できるため、すべての回文部分文字列を最初に計算してから、元の文字列を3つの回文部分文字列に分割できるかどうかを調べるためにトラバースできます。
(2)コード
class Solution {
public boolean checkPartitioning(String s) {
char[] c = s.toCharArray();
int len = s.length();
boolean[][] dp = new boolean[len][len];
for (int i = 0; i < len; i++)
for (int j = 0; j < len; j++)
dp[i][j] = false;
for (int i = 0; i < len; i++) {
//单个字母及延伸的回文字符串
int halflen = 0;
while (i - halflen >= 0 && i + halflen < len && c[i - halflen] == c[i + halflen])
dp[i - halflen][i + halflen++] = true;
}
for (int i = 1; i < len; i++) {
//相同的2个字母及延伸的回文字符串
if (c[i - 1] == c[i]) {
int halflen = 0;
while (i - 1 - halflen >= 0 && i + halflen < len && c[i - 1 - halflen] == c[i + halflen])
dp[i - 1 - halflen][i + halflen++] = true;
}
}
for (int l = 1; l < len - 1; l++) {
//l,r表示分割点,区间左闭右开
if (dp[0][l - 1])
for (int r = l + 1; r < len; r++)
if (dp[l][r - 1] && dp[r][len - 1])
return true;
}
return false;
}
};
(3)結果
実行時間:84ミリ秒、
すべてのJava送信でユーザーの68.28%を上回っています。メモリ消費量:42.2 MB、すべてのJava送信でユーザーの65.52%を上回っています。
3、その他
この問題は、線形時間計算量のManacher法でも解決できます。